Skip to content

FriendsOfREDAXO/pdfout

Repository files navigation

PdfOut für REDAXO!

PdfOut stellt den "HTML to PDF"-Converter dompdf, TCPDF, FPDI und PDF.js 5.x in REDAXO zur Verfügung.

Inhaltsverzeichnis

Installation

Die Installation erfolgt über den REDAXO-Installer, alternativ gibt es die aktuellste Beta-Version auf GitHub.

Neu in Version 10.x: PDF.js 5.x mit automatischem Update-System! Siehe PDF.js Update-System für Details.

Was kann PdfOut?

  • 🌈 HTML zu PDF: Wandelt HTML in hochwertige PDFs um
  • 🎨 Anpassbar: Ausrichtung, Schriftart, DPI und mehr
  • 🖼 Media Integration: Bilder direkt aus dem REDAXO Media Manager
  • 💾 Flexibel: Speichern oder direktes Streaming an Browser
  • 🔢 Automatik: Seitenzahlen und -zählung automatisch
  • 🔍 Viewer: Integrierter PDF-Viewer mit PDF.js 5.x
  • 🔒 Sicher: Passwortschutz und Berechtigungen
  • ✍️ Signiert: Digitale Signaturen für Authentizität
  • 🚀 Workflow: Optimierter REDAXO-Workflow (dompdf → Cache → Signierung)

Lass uns loslegen!

Quick Start: Das erste PDF in 3... 2... 1...

use FriendsOfRedaxo\PdfOut\PdfOut; 
$pdf = new PdfOut();
$pdf->setName('mein_erstes_pdf')
    ->setHtml('<h1>Hallo REDAXO-Welt!</h1><p>Mein erstes PDF mit PdfOut. Wie cool ist das denn?</p>')
    ->run();

Artikel-Inhalte als PDF

use FriendsOfRedaxo\PdfOut\PdfOut;
$pdf = new PdfOut();
$pdf->setName('artikel_als_pdf')
    ->addArticle(1)  // Hier die ID eures Artikels einsetzen
    ->run();

Erweiterte Konfiguration eines PDFs

use FriendsOfRedaxo\PdfOut\PdfOut;
$pdf = new PdfOut();

$pdf->setName('konfiguriertes_pdf')
    ->setPaperSize('A4', 'portrait')      // Setzt Papiergröße und Ausrichtung
    ->setFont('Helvetica')                // Setzt die Standardschriftart
    ->setDpi(300)                         // Setzt die DPI für bessere Qualität
    ->setAttachment(true)                 // Als Download statt Vorschau
    ->setRemoteFiles(true)                // Erlaubt externe Ressourcen
    ->setHtml($content, true)             // HTML mit Output Filter
    ->run();

Schicke Vorlagen für PDFs

$meineVorlage = '
<!DOCTYPE html>
<html>
<head>
    <style>
        body { font-family: Arial, sans-serif;}
        .kopf { background-color: #ff9900; padding: 10px; }
        .inhalt { margin: 20px; }
        .footer { position: fixed; bottom: 0; width: 100%; text-align: center; }
        .pagenum:before {
		content: counter(page);
        }
</style>

</style>
</head>
<body>
    <div class="kopf">Mein supercooler PDF-Kopf</div>
    <div class="inhalt">{{CONTENT}}</div>
    <div class="footer">Seite <span class="pagenum"></span> von: DOMPDF_PAGE_COUNT_PLACEHOLDER</div>
</body>
</html>';

use FriendsOfRedaxo\PdfOut\PdfOut;
$pdf = new PdfOut();
$pdf->setName('stylishes_pdf')
    ->setBaseTemplate($meineVorlage)
    ->setHtml('<h1>Wow!</h1><p>Dieses PDF sieht ja mal richtig schick aus!</p>')
    ->run();

PDFs speichern und verschicken

PDF speichern und gleichzeitig an den Browser senden? So geht's:

use FriendsOfRedaxo\PdfOut\PdfOut;
$pdf = new PdfOut();
$pdf->setName('mein_meisterwerk')
    ->setHtml('<h1>PDF-Kunst</h1>')
    ->setSaveToPath(rex_path::addonCache('pdfout'))
    ->setSaveAndSend(true)  // Speichert und sendet in einem Rutsch
    ->run();

Passwortgeschützte PDFs

Neuer empfohlener Workflow mit dompdf → Cache → TCPDF-Passwortschutz:

use FriendsOfRedaxo\PdfOut\PdfOut;

// Einfache Passwortschutz-Methode (direkte Ausgabe)
$pdf = new PdfOut();
$pdf->createPasswordProtectedDocument(
    '<h1>Geheimes Dokument</h1><p>Nur mit Passwort zugänglich!</p>',
    'meinPasswort123',
    'geschuetztes_dokument.pdf'
);

// Als Datei speichern (⭐ Neu!)
$pdf = new PdfOut();
$savedPath = $pdf->createPasswordProtectedDocument(
    $htmlContent,
    'meinPasswort123',
    'geschuetztes_dokument.pdf',
    '/pfad/zum/speicherort/',        // Speicherverzeichnis
    true                             // Original überschreiben = ja
);
echo "PDF gespeichert: " . $savedPath;

// Erweiterte Passwortschutz-Methode mit mehr Optionen und Speicherung
$pdf = new PdfOut();
$pdf->setPaperSize('A4', 'landscape')     // Alle dompdf-Settings werden verwendet!
    ->setFont('Helvetica')                // Schriftart
    ->setDpi(300)                         // Hohe Auflösung
    ->createPasswordProtectedWorkflow(
        $htmlContent,                     // HTML-Inhalt
        'userPasswort',                   // User-Passwort (zum Öffnen)
        'ownerPasswort',                  // Owner-Passwort (Vollzugriff)
        ['print', 'copy', 'modify'],      // Erlaubte Aktionen
        'vertraulich.pdf',                // Dateiname
        '',                               // Standard Cache
        '/speicherort/',                  // Speicherverzeichnis (⭐ Neu!)
        false                             // Original NICHT überschreiben (⭐ Neu!)
    );

Traditionelle TCPDF-Methode (falls direkter Zugriff benötigt):

$pdf = new TCPDF();
$pdf->SetProtection(
    ['print', 'copy'],  // Erlaubte Aktionen
    'user123',          // User-Passwort (zum Öffnen)
    'owner123'          // Owner-Passwort (Vollzugriff)
);

$pdf->AddPage();
$pdf->SetFont('dejavusans', '', 12);
$pdf->writeHTML('<h1>Geheimes Dokument</h1><p>Nur mit Passwort zugänglich!</p>');
$pdf->Output('geschuetzt.pdf', 'I');

Digitale Signaturen

Erstelle rechtsgültige, digital signierte PDFs:

// Einfache Signierung (direkt mit TCPDF)
require_once rex_path::addon('pdfout') . 'vendor/tecnickcom/tcpdf/tcpdf.php';

$pdf = new TCPDF();
$pdf->setSignature(
    $certificatePath,    // Pfad zum Zertifikat (.p12)
    $certificatePath,    // Pfad zum Zertifikat
    'password',          // Zertifikats-Passwort
    '',                  // Private Key (leer wenn in .p12)
    2,                   // Signatur-Typ
    [
        'Name' => 'Max Mustermann',
        'Location' => 'Deutschland',
        'Reason' => 'Dokument-Authentifizierung',
        'ContactInfo' => '[email protected]'
    ]
);

$pdf->AddPage();
$pdf->SetFont('dejavusans', '', 12);
$pdf->writeHTML('<h1>Signiertes Dokument</h1>');
$pdf->Output('signiert.pdf', 'I');

REDAXO Workflow: dompdf → Cache → Signierung

Der empfohlene Weg für komplexe PDFs mit Signierung:

use FriendsOfRedaxo\PdfOut\PdfOut;

// Neue vereinfachte Workflow-Methode (direkte Ausgabe)
$pdf = new PdfOut();
$pdf->createSignedDocument($htmlContent, 'dokument.pdf');

// Als Datei speichern (⭐ Neu!)
$pdf = new PdfOut();
$savedPath = $pdf->createSignedDocument(
    $htmlContent, 
    'dokument.pdf',
    '/pfad/zum/speicherort/',        // Speicherverzeichnis
    true                             // Original überschreiben = ja
);
echo "Signiertes PDF gespeichert: " . $savedPath;

// Oder mit erweiterten Optionen und Speicherung
$pdf->createSignedWorkflow(
    $htmlContent,                    // HTML-Inhalt
    $certificatePath,                // Zertifikatspfad
    $certificatePassword,            // Zertifikatspasswort
    ['Name' => 'Max Mustermann'],    // Signatur-Info
    'rechnung.pdf',                  // Dateiname
    '',                              // Standard Cache
    '/speicherort/',                 // Speicherverzeichnis (⭐ Neu!)
    false                            // Original NICHT überschreiben (⭐ Neu!)
);

Was passiert intern:

  1. dompdf erstellt hochwertiges PDF mit perfektem HTML/CSS-Support
  2. Zwischenspeicherung im Cache für Performance und Wiederverwendung
  3. FPDI + TCPDF importiert und signiert das PDF nachträglich
  4. Automatisches Aufräumen der temporären Dateien

PDF-Zusammenführung

Neue Workflow-Methoden für das Zusammenführen von PDFs:

use FriendsOfRedaxo\PdfOut\PdfOut;

// HTML-Inhalte zu einem PDF zusammenführen (empfohlen, direkte Ausgabe)
$htmlContents = [
    '<h1>Dokument 1</h1><p>Projektübersicht...</p>',
    '<h1>Dokument 2</h1><p>Feature-Liste...</p>',
    '<h1>Dokument 3</h1><p>Fazit...</p>'
];

$pdf = new PdfOut();
$pdf->setPaperSize('A4', 'portrait')    // Alle dompdf-Settings werden verwendet
    ->setDpi(300)                       // Hohe Auflösung
    ->mergeHtmlToPdf(
        $htmlContents,                  // Array mit HTML-Inhalten
        'zusammengefuehrtes_dokument.pdf', // Ausgabe-Dateiname
        true                           // Trennseiten zwischen Dokumenten
    );

// HTML-Inhalte zusammenführen und als Datei speichern (⭐ Neu!)
$savedPath = $pdf->mergeHtmlToPdf(
    $htmlContents,                      // Array mit HTML-Inhalten
    'zusammengefuehrtes_dokument.pdf',  // Ausgabe-Dateiname
    true,                              // Trennseiten zwischen Dokumenten
    '/pfad/zum/speicherort/',          // Speicherverzeichnis (⭐ Neu!)
    false                              // Original NICHT überschreiben (⭐ Neu!)
);
echo "Zusammengeführtes PDF gespeichert: " . $savedPath;

// Bestehende PDF-Dateien zusammenführen
$pdfPaths = [
    '/path/to/document1.pdf',
    '/path/to/document2.pdf',
    '/path/to/document3.pdf'
];

// Direkte Ausgabe
$pdf->mergePdfs(
    $pdfPaths,                         // Array mit PDF-Dateipfaden
    'merged_document.pdf',             // Ausgabe-Dateiname
    false                              // Keine Trennseiten
);

// Als Datei speichern (⭐ Neu!)
$savedPath = $pdf->mergePdfs(
    $pdfPaths,                         // Array mit PDF-Dateipfaden
    'merged_document.pdf',             // Ausgabe-Dateiname
    false,                             // Keine Trennseiten
    '',                                // Standard Cache
    '/speicherort/',                   // Speicherverzeichnis (⭐ Neu!)
    true                               // Original überschreiben = ja (⭐ Neu!)
);

Vorteile der PDF-Zusammenführung:

  • Alle dompdf-Settings werden bei HTML-Merge berücksichtigt
  • Optimale Qualität durch dompdf für HTML-Rendering
  • Automatisches Aufräumen temporärer Dateien
  • Flexible Optionen für Trennseiten zwischen Dokumenten

Erweiterte Methoden

Basis-Methoden (PdfOut-Klasse)

setPaperSize(string|array $size = 'A4', string $orientation = 'portrait')

Setzt das Papierformat und die Ausrichtung für das PDF. Als $size kann entweder ein Standardformat wie 'A4', 'letter' oder ein Array mit [width, height] in Punkten übergeben werden.

$pdf->setPaperSize('A4', 'landscape');  // Querformat A4
$pdf->setPaperSize([841.89, 595.28], 'portrait');  // Benutzerdefinierte Größe

setBaseTemplate(string $template, string $placeholder = '{{CONTENT}}')

Setzt ein Grundtemplate für das PDF. Der Platzhalter wird durch den eigentlichen Inhalt ersetzt. Besonders nützlich für einheitliches Layout über mehrere PDFs.

addArticle(int $articleId, ?int $ctype = null, bool $applyOutputFilter = true)

Ermöglicht das Hinzufügen von REDAXO-Artikelinhalten:

  • $articleId: Die ID des Artikels
  • $ctype: Optional die ID des Content-Types
  • $applyOutputFilter: Ob der OUTPUT_FILTER angewendet werden soll

mediaUrl(string $type, string $file)

Generiert korrekte URLs für Media-Manager-Bilder im PDF:

$imageUrl = PdfOut::mediaUrl('media_type', 'bild.jpg');
$html = '<img src="' . $imageUrl . '" alt="Mein Bild">';

viewer(string $file = '')

Erzeugt eine URL für den integrierten PDF-Viewer:

// Als Download-Link
echo '<a href="' . PdfOut::viewer('/media/dokument.pdf') . '" download>PDF anzeigen</a>';

// Als iFrame eingebettet
echo '<iframe src="' . PdfOut::viewer('/media/dokument.pdf') . '"></iframe>';

Neue Workflow-Methoden

createSignedDocument(string $html, string $filename = 'document.pdf', string $saveToPath = '', bool $replaceOriginal = false)

Vereinfachte Methode für den kompletten Workflow. Erstellt PDF mit dompdf, speichert zwischen und signiert nachträglich.

// Direkte Ausgabe
$pdf = new PdfOut();
$pdf->createSignedDocument($htmlContent, 'rechnung.pdf');

// Als Datei speichern (⭐ Neu!)
$savedPath = $pdf->createSignedDocument(
    $htmlContent, 
    'rechnung.pdf',
    '/speicherort/',     // Speicherverzeichnis 
    true                 // Original überschreiben
);

createSignedWorkflow(string $html, string $certPath, string $certPassword, array $signatureInfo, string $filename, string $cacheDir, string $saveToPath, bool $replaceOriginal)

Erweiterte Workflow-Methode mit vollständiger Kontrolle über Zertifikat, Signatur-Informationen und Dateispeicherung.

$pdf = new PdfOut();
$pdf->createSignedWorkflow(
    $htmlContent,
    '/path/to/certificate.p12',
    'certificate_password',
    [
        'Name' => 'Max Mustermann',
        'Location' => 'Deutschland', 
        'Reason' => 'Rechnung signiert',
        'ContactInfo' => '[email protected]'
    ],
    'signierte_rechnung.pdf'
);

TCPDF-Integration für erweiterte Features

Passwort-Schutz mit SetProtection()

$pdf = new TCPDF();
$pdf->SetProtection(
    $permissions,    // Array mit erlaubten Aktionen
    $userPassword,   // Passwort zum Öffnen
    $ownerPassword   // Master-Passwort
);

Verfügbare Berechtigungen:

  • 'print' - Drucken erlaubt
  • 'copy' - Text kopieren erlaubt
  • 'modify' - Dokument bearbeiten
  • 'annot-forms' - Kommentare/Formulare
  • 'fill-forms' - Formulare ausfüllen
  • 'extract' - Seiten extrahieren
  • 'assemble' - Seiten zusammenfügen
  • 'print-high' - Hochwertiges Drucken

Digitale Signaturen mit setSignature()

$pdf = new TCPDF();
$pdf->setSignature(
    $certificate,     // Pfad zum Zertifikat (.p12)
    $certificate,     // Pfad zum Zertifikat (wiederhole für .p12)
    $password,        // Zertifikats-Passwort
    '',              // Private Key (leer für .p12)
    2,               // Signatur-Typ (2 = fortgeschritten)
    $info            // Array mit Signatur-Informationen
);

FPDI für PDF-Import

Für nachträgliche Bearbeitung existierender PDFs:

require_once rex_path::addon('pdfout') . 'vendor/setasign/fpdi/src/autoload.php';

$pdf = new setasign\Fpdi\Tcpdf\Fpdi();
$pageCount = $pdf->setSourceFile('existing.pdf');

for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
    $pdf->AddPage();
    $template = $pdf->importPage($pageNo);
    $pdf->useTemplate($template);
}

Tipps für die Optimierung

Performance-Optimierung

  • CSS inline im HTML definieren statt externe Dateien
  • Auf große CSS-Frameworks verzichten
  • Bilder in optimierter Größe verwenden
  • OPcache für bessere PHP-Performance aktivieren

Bilder und Media Manager

  • Relative Pfade vom Frontend-Ordner: media/bild.jpg
  • Media Manager URLs immer als absolute URLs
  • setRemoteFiles(true) für externe Ressourcen

CSS und Schriftarten

  • Numerische font-weight Angaben vermeiden
  • Google Fonts lokal einbinden
  • Bei Schriftproblemen: isFontSubsettingEnabled auf false setzen

Kopf- und Fußzeilen

  • Fixierte Divs direkt nach dem body-Tag platzieren
  • Seitenzahlen über CSS count oder Platzhalter

Anwendungsfälle & Best Practices

Rechnungen und Geschäftsdokumente

// Rechnung mit Signatur für Rechtsgültigkeit
$pdf = new PdfOut();
$pdf->createSignedWorkflow(
    $rechnungHtml,
    $firmenzertifikat,
    $zertifikatPasswort,
    ['Name' => 'Musterfirma GmbH', 'Reason' => 'Rechnung rechtsgültig signiert'],
    'rechnung_' . $rechnungsnummer . '.pdf'
);

Vertrauliche Berichte

// Passwortgeschützter Bericht mit eingeschränkten Rechten
$pdf = new TCPDF();
$pdf->SetProtection(['print'], $benutzerPasswort, $adminPasswort);
$pdf->AddPage();
$pdf->writeHTML($berichtContent);
$pdf->Output('vertraulicher_bericht.pdf', 'I');

Zertifikate und Urkunden

// Hochauflösendes Zertifikat mit Signatur
$pdf = new PdfOut();
$pdf->setDpi(300)  // Hohe Auflösung für Druck
    ->setPaperSize('A4', 'landscape');

$pdf->createSignedDocument($zertifikatHtml, 'zertifikat.pdf');

Formulare zum Ausfüllen

// PDF-Formular mit Schutz vor Strukturänderungen
$pdf = new TCPDF();
$pdf->SetProtection(['fill-forms', 'print'], '', $ownerPassword);
// ... Formularfelder hinzufügen
$pdf->Output('formular.pdf', 'I');

Archivierung und Compliance

// Langzeitarchivierung mit Signatur und Metadaten
$pdf = new TCPDF();
$pdf->SetCreator('REDAXO CMS');
$pdf->SetTitle('Archiviertes Dokument');
$pdf->SetSubject('Compliance-Archiv');
$pdf->SetKeywords('Archiv, Compliance, ' . date('Y'));

$pdf->setSignature($archivZertifikat, $archivZertifikat, $password, '', 2, [
    'Name' => 'Automatisches Archivsystem',
    'Reason' => 'Compliance-Archivierung',
    'Location' => 'Deutschland'
]);

Systemvoraussetzungen

  • DOM-Erweiterung
  • MBString-Erweiterung
  • php-font-lib
  • php-svg-lib
  • gd-lib oder ImageMagick

Empfohlen:

  • OPcache für bessere Performance
  • GD oder IMagick/GMagick für Bildverarbeitung
  • OpenSSL für digitale Signaturen

PDF.js Update-System

PdfOut 10.x enthält ein neues automatisiertes Update-System für PDF.js:

🚀 Ein-Befehl Updates

# Update auf neueste PDF.js Version
./scripts/update-pdfjs.sh

# Update auf spezifische Version  
./scripts/update-pdfjs.sh 5.4.394

# Verfügbare Updates prüfen
npm run check-updates

✨ Neue Features in PDF.js 5.x

  • Vollständige Distribution: Kompletter Viewer mit allen Komponenten
  • GitHub-Integration: Direkte Downloads von offiziellen Releases
  • Optimiert: Ausschluss von CJK-Character-Maps spart 1.6MB
  • Automatisiert: Ein Befehl für komplette Updates
  • Zukunftssicher: Unterstützt alle kommenden PDF.js Versionen

📖 Ausführliche Anleitung

Siehe PDFJS_UPDATE.md für den kompletten Workflow und Konfigurationsmöglichkeiten.

Demo-Seite

PdfOut enthält eine umfassende Demo-Seite mit funktionierenden Beispielen:

  • Einfaches PDF: Grundlegende PDF-Erstellung mit dompdf
  • Passwortschutz: Sichere PDFs mit konfigurierbaren Berechtigungen
  • Digitale Signaturen: Rechtsgültige Signierung mit TCPDF
  • Nachträgliche Signierung: FPDI-basierte Signierung existierender PDFs
  • REDAXO-Workflow: Optimaler Workflow für komplexe, signierte PDFs

Die Demo zeigt auch:

  • Test-Zertifikat-Generierung
  • System-Status-Übersicht
  • Sicherheits-Best-Practices
  • Code-Beispiele für alle Features

Verwendete Bibliotheken & Lizenzen

PdfOut baut auf bewährten Open-Source-Bibliotheken auf:

PDF-Generierung

dompdf

TCPDF

FPDI

CSS- und HTML-Verarbeitung

sabberworm/php-css-parser

masterminds/html5

php-font-lib & php-svg-lib

PDF-Viewer

PDF.js

Lizenzen im Detail

LGPL (Lesser General Public License)

Die LGPL-lizenzierten Komponenten (dompdf, TCPDF, php-font-lib) erlauben:

  • ✅ Kommerzielle Nutzung
  • ✅ Einbindung in proprietäre Software
  • ✅ Modifikation der Bibliotheken
  • ⚠️ Modifikationen an LGPL-Code müssen unter LGPL bleiben

MIT License

Die MIT-lizenzierten Komponenten erlauben:

  • ✅ Vollständig freie Nutzung
  • ✅ Kommerzielle Nutzung ohne Einschränkungen
  • ✅ Modifikation und Weiterverteilung
  • ✅ Einbindung in proprietäre Software

Apache 2.0 (PDF.js)

  • ✅ Kommerzielle Nutzung
  • ✅ Patent-Grant (Schutz vor Patent-Klagen)
  • ✅ Trademark-Schutz

Support & Credits

Wo finde ich Hilfe?

Team

Friends Of REDAXO
http://www.redaxo.org
https://github.com/FriendsOfREDAXO

Projekt-Lead
Thomas Skerbis

Danke an

Sponsors

Version 10.0.0

Lizenz

PdfOut selbst: MIT-Lizenz

Verwendete Bibliotheken:

  • dompdf: LGPL v2.1
  • TCPDF: LGPL v3+
  • FPDI: MIT
  • PDF.js 5.x: Apache 2.0 (automatisch aktualisiert)
  • php-css-parser: MIT
  • html5-php: MIT

Alle Lizenzen sind kompatibel und erlauben sowohl private als auch kommerzielle Nutzung.

About

PDF-Generator dompdf und pdf.js für REDAXO

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Contributors 21