Writer: PDF 2.0-Serializer + Xref
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Das Writer-Modul serialisiert ein Dokument zu PDF-Bytes. Es wählt eine Versionsstrategie, schreibt den Objektgraphen und gibt die Querverweisstruktur sowie den Trailer aus.
Installation
Abschnitt betitelt „Installation“composer require nextpdf/core:^3Konzeptioneller Überblick
Abschnitt betitelt „Konzeptioneller Überblick“PdfWriter ist der Einstiegspunkt. Die Methode write() nimmt ein DocumentData-Wertobjekt entgegen. Sie gibt das vollständige PDF als Byte-String zurück. Der Writer baut den Objektgraphen auf, vergibt Objektnummern, erfasst Byte-Offsets und schreibt die Querverweisstruktur zuletzt.
Der Writer verwendet pro Aufruf eine Serialisierungsstrategie. Das Interface PdfSerializationStrategy definiert vier Methoden: writeHeader(), getCatalogVersion(), writeXrefAndTrailer() und usesXrefStream(). Drei Strategien implementieren es. Pdf20StreamStrategy schreibt den Header %PDF-2.0, setzt die Katalogversion auf /2.0 und gibt einen Querverweis-Stream aus. Pdf17TableStrategy schreibt %PDF-1.7 und eine klassische Querverweis-table. Pdf14TableStrategy schreibt %PDF-1.4 und eine Querverweistabelle. PdfWriter wählt die Strategie über ein match auf DocumentData::$outputProfile. Die Voreinstellung ist Pdf20StreamStrategy.
Das Enum PdfOutputProfile enthält die drei Zielversionen: Pdf20, Pdf17 und Pdf14. Das Enum stellt headerVersion(), catalogVersion(), allowsObjectStreams() und usesXrefStream() bereit. Ein Konformitätsmodus für die Archivierung überschreibt das gewählte Profil vor der Strategieauswahl. Pdf14FeatureGuard weist PDF 2.0-Features zurück, wenn das Profil Pdf14 ausgewählt ist.
Ein Querverweis-Stream bildet jede Objektnummer auf ihren Byte-Offset ab — ISO 32000-2 §7. Inkrementelle Aktualisierungen hängen neue Objekte an das Dateiende an — ISO 32000-2 §7.5.6. Der Writer maskiert jeden literalen String über den kanonischen Seam PdfStringEscaper::escapeLiteral(), der der normativen Maskierungstabelle in ISO 32000-2 §7.3.4.2 folgt (ADR-015).
Der Writer unterstützt deterministische Ausgaben. setDeterministicMode() fixiert Objektbezeichner und die Reihenfolge der Dictionary-Schlüssel. setReproducibleClock() fixiert den Dokument-Zeitstempel. Sind beide fixiert, erzeugt eine feste Eingabe eine bytegenau identische Ausgabe. Die Methode writeChunked() liefert einen Generator, der das PDF in Chunks fester Größe ausgibt. Streaming/StreamingPdfWriter schreibt jeweils eine Seite in einen vom Aufrufer bereitgestellten Stream — für Dokumente, die das Speicherbudget überschreiten.
Linearizer schreibt ein fertiges PDF in ein linearisiertes Layout um. Er platziert die erste Seite früh, damit ein Viewer sie anzeigen kann, bevor der vollständige Download abgeschlossen ist. shadowValidate() prüft die Umschreibung, ohne die Eingabe zu verändern.
Vorsicht.
PdfWriter.phpundLinearizer.phpsind Byte-Offset- und objektgraph-kritisch (Gefahrenzonen im Manifest). Ändern Sie weder die Objektnummerierung noch die Xref-Offset-Arithmetik ohne die Golden-Suite des Writers.
API-Oberfläche
Abschnitt betitelt „API-Oberfläche“| Klasse | Wichtige Methoden | Rolle |
|---|---|---|
PdfWriter | write(DocumentData): string, writeChunked(DocumentData, int): Generator, setDeterministicMode(), setReproducibleClock(), setOutputColorProfile(), getLastXrefOffset(), getFileId() | Primärer Serializer |
PdfSerializationStrategy (Interface) | writeHeader(), getCatalogVersion(), writeXrefAndTrailer(), usesXrefStream() | Vertrag der Versionsstrategie |
Pdf20StreamStrategy | writeHeader() → %PDF-2.0, getCatalogVersion() → /2.0, usesXrefStream() → true | PDF 2.0-Xref-Stream-Strategie |
Pdf17TableStrategy | writeHeader() → %PDF-1.7, Xref-Tabelle | PDF 1.7-Xref-Tabellen-Strategie |
Pdf14TableStrategy | writeHeader() → %PDF-1.4, Xref-Tabelle | PDF 1.4-Xref-Tabellen-Strategie |
PdfOutputProfile (Enum) | Pdf20, Pdf17, Pdf14; headerVersion(), catalogVersion(), allowsObjectStreams() | Zielversionsauswahl |
PdfXrefWriter | generateFileId(), finalizeTrailerAndXref() | Datei-ID- + trailer/xref-Finalisierung |
Linearizer | linearize(string): string, shadowValidate(string): array | Fast-Web-View-Umschreibung |
Streaming\StreamingPdfWriter | open(), newPage(), close() | Single-Pass-Streaming-Writer |
Führen Sie composer docs:generate-api-php -- --module=Writer aus, um die vollständige PHPDoc-Tabelle zu erhalten.
Code-Beispiel — Schnellstart
Abschnitt betitelt „Code-Beispiel — Schnellstart“Quelle: examples/02-pdf-factory.php.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Writer\PdfWriter;
$writer = new PdfWriter();$pdfBytes = $writer->write($documentData);
file_put_contents('out.pdf', $pdfBytes);Das Standardprofil ist PDF 2.0. Die Ausgabe beginnt mit %PDF-2.0 und endet mit einem Querverweis-Stream.
Code-Beispiel — Produktion
Abschnitt betitelt „Code-Beispiel — Produktion“Dieses Beispiel fixiert Determinismus und eine feste Uhr für bytegenau identische Ausgaben und streamt anschließend in festen Chunks.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use DateTimeImmutable;use NextPDF\Writer\PdfWriter;use NextPDF\Writer\ReproducibleClock;
$pinned = new DateTimeImmutable('2026-01-01T00:00:00Z');
$writer = new PdfWriter();$writer->setDeterministicMode($pinned, 'nextpdf-fixed-file-id');$writer->setReproducibleClock(new ReproducibleClock($pinned));
$out = fopen('php://output', 'wb');foreach ($writer->writeChunked($documentData, chunkSize: 65536) as $chunk) { fwrite($out, $chunk);}fclose($out);Sonderfälle & Stolperfallen
Abschnitt betitelt „Sonderfälle & Stolperfallen“- Pro
write()-Aufruf läuft eine Strategie. Der Writer setzt die Strategie bei jedem Aufruf aus dem Profil zurück. Ein vorheriger Aufruf überträgt seine Version nicht auf den nächsten. - Ein Konformitätsmodus für die Archivierung überschreibt das angeforderte Profil. Ein PDF/A-3-Build erzwingt PDF 1.7. Ein PDF/A-4-Build erzwingt PDF 2.0.
- Bytegenau identische Ausgabe erfordert beide Fixierungen. Setzen Sie den deterministischen Modus und eine reproduzierbare Uhr. Eine Fixierung allein reicht nicht.
writeChunked()liefert einen Generator. Konsumieren Sie ihn vollständig. Ein partielles Lesen erzeugt ein abgeschnittenes, ungültiges PDF.Linearizerschreibt Querverweis-Offsets um. Führen SieshadowValidate()in einer Pipeline, die eine fehlgeschlagene Umschreibung nicht verträgt, zuerst aus.Pdf14TableStrategyistfinal readonly. Der PDF 1.4-Pfad weist PDF 2.0-Features überPdf14FeatureGuardzurück, statt sie herabzustufen.
Performance
Abschnitt betitelt „Performance“Die Serialisierung ist linear zur Objektanzahl und zur Gesamt-Byte-Größe. Der Querverweis-Stream fügt einen Durchlauf über die Objekttabelle hinzu. writeChunked() hält das zusammengesetzte Dokument, gibt es aber in begrenzten Abschnitten aus, sodass der Spitzenspeicher die Dokumentgröße plus einen Chunk beträgt. Streaming\StreamingPdfWriter hält nicht das gesamte Dokument — es ist der Pfad für Eingaben, die größer als das Speicherbudget sind. Das Budget des Referenz-Workloads beträgt 1500 ms Wandzeit und 64 MB Spitzenspeicher. Die Linearisierung fügt einen zweiten vollständigen Durchlauf und einen Messdurchlauf hinzu. Planen Sie das Budget dafür explizit ein.
Sicherheitshinweise
Abschnitt betitelt „Sicherheitshinweise“Der Writer serialisiert einen vertrauenswürdigen Objektgraphen im Speicher. Die Hauptbedrohungen gehen von seinen Eingaben aus. Jeder literale String durchläuft den kanonischen PdfStringEscaper::escapeLiteral() (ADR-015), sodass eingebettete Steuerbytes nicht aus einem String-Token ausbrechen können. Die Verschlüsselung ist über PdfEncryptionWriter und den Trailer-Eintrag /Encrypt eingebunden. Public-Key-Verschlüsselung wird mit einer expliziten Exception zurückgewiesen, statt still herabgestuft zu werden. Der deterministische Modus und der reproduzierbare-Uhr-Modus entfernen Seitenkanäle über Zeitstempel und Reihenfolge aus der Ausgabe. Siehe /modules/core/security/ für das Bedrohungsmodell des Dokuments und die Vertrauensgrenze der Verschlüsselung.
Konformität
Abschnitt betitelt „Konformität“Der Writer erzeugt PDF 2.0-Dateistrukturen: den Header %PDF-2.0, eine Katalogversion /2.0, einen Querverweis-Stream und die Maskierung literaler Strings gemäß der Maskierungstabelle in ISO 32000-2 §7.3.4.2. Das sind Implementierungsfakten. Der Nachweis liegt in src/Writer/Pdf20StreamStrategy.php, src/Writer/PdfSerializationStrategy.php und der Strategieauswahl in src/Writer/PdfWriter.php; ausgeübt wird er durch tests/Unit/Writer/ (192 Tests, darunter die Suiten Pdf20StreamStrategy, PdfXrefWriter und Linearizer*) und die Baseline tests/Golden/PdfWriter/PdfWriterGoldenBaselineSmokeTest.
Das ist keine Behauptung vollständiger PDF 2.0-Konformität. Vollständige ISO 32000-2-Konformität ist eine Eigenschaft eines vollständigen Dokuments, das von einem externen Oracle validiert wird, nicht des Serializers allein. End-to-End-Konformität wird nur dort zugesichert, wo ein Oracle sie bestätigt: tests/Integration/Accessibility/VeraPdfUa2GoldenTest validiert eine erzeugte Fixture gegen veraPDF für PDF/UA-2, und tests/Standards/Profile/PdfRConformanceTest deckt das PDF/R-Profil ab. Der veraPDF-Golden-Test wird übersprungen, wenn das veraPDF-Binary auf dem Runner fehlt; er ist also ein Opt-in-Oracle-Gate, kein bedingungsloses. Setzen Sie VERAPDF_BINARY, um ihn auszuführen. Die Auswahl des Archivierungsprofils (PDF/A-3 → PDF 1.7, PDF/A-4 → PDF 2.0) wird durch ADR-011 und den Konformitätsmodus entschieden und durch die Konformitäts-Suiten in /modules/core/conformance/ validiert. Außerhalb dieser oracle-gestützten Profile formulieren Sie, dass der Writer „PDF 2.0-Strukturen erzeugt; die Konformität wird durch veraPDF für das PDF/UA-2-Profil validiert“, statt uneingeschränkte Konformität zu behaupten.