Ein PDF ist ein Container: eingebettete Dateien und zugeordnete Daten
Spec: ISO 32000-2, §7.11.4ISO 32000-2 §7.11.4Spec: ISO 32000-2, §14.13ISO 32000-2 §14.13Spec: ISO 19005-3, PDF/A-3ISO 19005-3 PDF/A-3
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Die meisten Menschen stellen sich ein PDF als einen Stapel Seiten vor. Das ist der Teil, den Sie sehen. Aber ein PDF ist auch ein Container, und es kann ganze andere Dateien in sich tragen – eine Tabellenkalkulation, eine XML-Nutzlast, das ursprüngliche Quelldokument – gebündelt in derselben einzelnen Datei, die Sie jemand anderem übergeben.
Diese Seite erklärt, wie das funktioniert: den eingebetteten Dateistream, der die Bytes speichert, den Namensbaum, der sie auflistet, und den einen Schlüssel, der entscheidet, ob ein Anhang einfach nur dasitzt oder tatsächlich etwas bedeutet.
Warum das wichtig ist
Abschnitt betitelt „Warum das wichtig ist“Ein untypisierter und ein typisierter Anhang sehen für einen Menschen identisch aus. Beide sind eine Datei, die in einem PDF mitreist, und – in dieser Engine – sind beide dem Dokument zugeordnet. Der Unterschied besteht darin, dass der eine einer Maschine sagt, wofür er da ist, und der andere die Beziehung leer lässt, damit die Maschine rät.
Dieser Unterschied entscheidet alles bei einer hybriden E-Rechnung. Eine Steuerplattform liest nicht Ihre Rechnungsseite; sie liest das XML, das Sie eingebettet haben. Wenn dieses XML als undifferenzierter Blob angehängt ist statt als die Rechnungs-Daten für das sichtbare Dokument, hat ein konformer Reader keine verlässliche Möglichkeit zu erkennen, dass es die zu verarbeitende Nutzlast ist. Die Seite sieht perfekt aus. Die Rechnung wird abgelehnt. Der Fehler trifft Tage später ein, mit einer zurückgehaltenen Zahlung im Schlepptau.
Die Beziehung in der Schicht, die die Datei erzeugt, richtig zu setzen, ist weitaus günstiger, als sie eine abgelehnte Rechnung nach der anderen herauszufinden.
Die Kurzfassung
Abschnitt betitelt „Die Kurzfassung“- Ein PDF kann die Bytes jeder beliebigen Datei einbetten als eingebetteten Dateistream (Spec: ISO 32000-2, §7.11.4ISO 32000-2 §7.11.4). Der Stream trägt die Daten plus ein kleines Parameter-Dictionary: ursprüngliche Größe, Daten und eine Prüfsumme.
- Eingebettete Dateien werden im
EmbeddedFiles-Namensbaum katalogisiert, sodass ein Reader sie namentlich aufzählen kann, ohne das gesamte Dokument zu durchsuchen. - Eine zugeordnete Datei geht einen Schritt weiter: Sie deklariert eine
AFRelationship(Spec: ISO 32000-2, §7.11.3ISO 32000-2 §7.11.3) – einen von acht Standardwerten (Source,Data,Alternative,Supplement,EncryptedPayload,FormData,Schema,Unspecified) oder einen benutzerdefinierten Wert –, der angibt, wie die Datei mit dem Inhalt zusammenhängt, an den sie angehängt ist. - Diese typisierte Beziehung ist der Mechanismus hinter hybriden E-Rechnungen (ZUGFeRD / Factur-X) und PDF/A-3-Anhängen (Spec: ISO 19005-3, PDF/A-3ISO 19005-3 PDF/A-3).
- NextPDF unterstützt die rohen Container-Primitiven im Core:
embedFile()undembedFileFromString()mit einer expliziten Beziehung. Advanced-Editionen fügen den dedizierten EN-16931- / ZUGFeRD- / Factur-X-E-Rechnungs-Embedder auf diesen Primitiven obendrauf hinzu.
Wie NextPDF dabei vorgeht
Abschnitt betitelt „Wie NextPDF dabei vorgeht“Stellen Sie es sich als zwei aufeinandergestapelte Schichten vor.
Die untere Schicht ist die Speicherung. Ein eingebetteter Dateistream
(Spec: ISO 32000-2, §7.11.4ISO 32000-2 §7.11.4) sind die Bytes der
Originaldatei, eingehüllt in ein PDF-Stream-Objekt, mit einem Parameter-Dictionary,
das die ursprüngliche Größe, das Änderungsdatum und eine Prüfsumme der
unkomprimierten Daten erfasst. Der Stream wird über ein Dateispezifikations-Dictionary
erreicht, dessen /EF-Dictionary auf den eingebetteten Dateistream zeigt – der
Stream selbst trägt kein /EF. Ein Reader kann die Datei Byte für Byte wieder
herausziehen. Damit diese Dateien auffindbar sind, hält der Dokumentkatalog einen
EmbeddedFiles-Namensbaum – eine sortierte Zuordnung von einem Namen zu jeder
Dateispezifikation –, sodass ein Reader auflisten kann „hier sind die 3 Dateien in
diesem PDF”, ohne jede Seite zu durchlaufen.
Die obere Schicht ist die Bedeutung. Für sich genommen ist eine eingebettete
Datei einfach nur vorhanden. Der Mechanismus der zugeordneten Dateien
(Spec: ISO 32000-2, §14.13ISO 32000-2 §14.13) hängt eine Datei an etwas an –
das gesamte Dokument, eine Seite, ein Grafikobjekt – und versieht sie mit einer
AFRelationship. ISO 32000-2 definiert ein kleines Vokabular von acht Standardwerten
(Spec: ISO 32000-2, §7.11.3ISO 32000-2 §7.11.3) und erlaubt auch
benutzerdefinierte Werte; jeder Standardwert beantwortet eine präzise Frage:
AFRelationship | Was er über die Datei aussagt |
|---|---|
Source | Dies ist das Quellmaterial, aus dem der sichtbare Inhalt erzeugt wurde (zum Beispiel das ursprüngliche Textverarbeitungsdokument). |
Data | Dies sind strukturierte Daten, die an den sichtbaren Inhalt gebunden sind – der kanonische Fall ist das Rechnungs-XML hinter einer gerenderten Rechnungsseite. |
Alternative | Dies ist eine alternative Darstellung desselben Inhalts (zum Beispiel eine Audio- oder Videoversion). |
Supplement | Dies ist ergänzendes Material, das den Inhalt erweitert, aber nicht Teil davon ist. |
EncryptedPayload | Die eingebettete Datei ist eine verschlüsselte Nutzlast, die das PDF als undurchsichtigen Blob umhüllt. |
FormData | Die Datei ist Formulardaten (FDF, XFDF oder eine XML-Formularnutzlast). |
Schema | Die Datei ist ein Schema, das die Struktur einer Data-Datei beschreibt (zum Beispiel ein XSD für XML-Daten oder ein JSON Schema). |
Unspecified | Die Beziehung wird bewusst nicht angegeben. Ehrlich, aber es sagt einer Maschine nichts. |
Über diese acht hinaus erlaubt der Standard außerdem anwendungsspezifische benutzerdefinierte Beziehungswerte, sodass das Vokabular erweiterbar statt fest ist.
Eine zugeordnete Datei wird durch zwei zusammenwirkende Dinge definiert, nicht durch
einen Schlüssel allein. Die /AF-Zuordnung bindet die Dateispezifikation an einen
Teil des Dokuments; der AFRelationship-Schlüssel in der Dateispezifikation gibt
dann die semantische Beziehung an. Der /AF-Eintrag am Zuordnungspunkt (dem
Dokumentkatalog, einer Seite oder einem Objekt) ist ein Array – dieses Array
enthält eine oder mehrere Dateispezifikations-Dictionarys, üblicherweise als
indirekte Referenzen; /AF ist keine einzelne Referenz. Eine dokumentweite
zugeordnete Datei ist die Dateispezifikation, die im /AF-Array des Dokumentkatalogs
aufgeführt ist und ihre AFRelationship trägt. Markieren Sie diese
Tabellenkalkulation als Unspecified, und Sie haben sie dem Dokument zugeordnet,
aber einer Maschine nichts darüber gesagt, warum. Markieren Sie dieselbe
Tabellenkalkulation als Data, und Sie haben jedem konformen Reader gesagt, was sie
ist und wofür sie da ist. Die Bytes sind dieselben. Die Semantik ist es nicht.
Deshalb ist der E-Rechnungs-Fall nicht „eine XML-Datei anhängen”. Es ist „dieses XML
als die Data-zugeordnete Datei für dieses Dokument einbetten, in einem konformen
PDF/A-3-Träger” – wobei die Gültigkeit der Rechnung und die rechtliche Akzeptanz
separate Prüfungen bleiben, die der Träger nicht durchführt. Der Ablauf hat vier
Phasen, und die Reihenfolge ist es, die ihn korrekt hält.
- Store the bytesThe file is wrapped in an embedded file stream with its size, dates, and a checksum (ISO 32000-2 §7.11.4).
- Register it by nameThe file specification is added to the EmbeddedFiles name tree so a reader can enumerate attachments without scanning the document.
- Declare the relationshipAn AFRelationship value (one of the eight standard values such as Source or Data) marks how the file relates to the content, associated at the document level (ISO 32000-2 §14.13.3).
- Make it archivalA PDF/A-3 carrier permits the embedded payload to ride inside one conforming archival PDF/A document; invoice validity and legal acceptance remain separate checks (ISO 19005-3).
Diese vierte Phase ist der Grund, warum PDF/A-3 als eigenes Profil existiert. Frühere
Archivierungsprofile schränkten ein, was eingebettet werden durfte; PDF/A-3
(Spec: ISO 19005-3, PDF/A-3ISO 19005-3 PDF/A-3) ist der Teil, der Dateien
jedes Formats erlaubt, in einem konformen Archivdokument mitzureisen. Es erlaubt
die eingebettete Nutzlast – es validiert diese Nutzlast nicht und verleiht keinen
rechtlichen Status. Ohne ihn könnte die hybride Rechnung – eine Datei, die zugleich
die Seite ist, die eine Person liest, und die Daten, die ein Steuersystem
verarbeitet – überhaupt kein konformes Archiv-PDF/A-Dokument sein; ob die Rechnung
gültig und rechtlich akzeptiert ist, bleibt eine separate Frage. Der dedizierte
E-Rechnungs-Embedder, den Advanced-Editionen hinzufügen, ist die Bequemlichkeitsnaht
über genau diesem: Er bettet die Nutzlast ein, setzt die Beziehung auf Data und
registriert sie korrekt, sodass Sie die Container-Verrohrung nicht von Hand
zusammensetzen. Die tiefere Rechnungs- und Archivierungsmechanik liegt auf den zwei
unten verlinkten Nachbarseiten; auf dieser Seite geht es um den Container, auf dem
beide stehen.
Praktisches Beispiel
Abschnitt betitelt „Praktisches Beispiel“Ein kleines, vollständiges Programm. Die zwei Aufrufe, auf die es ankommt, sind der
Unterschied zwischen einer untypisierten und einer typisierten zugeordneten
Datei – und die Beziehung ist ein explizites Argument, das Sie setzen sollten. In
dieser Engine erzeugen beide Aufrufe eine zugeordnete Datei: embedFile() und
embedFileFromString() registrieren die Dateispezifikation stets im /AF-Array des
Dokumentkatalogs, sodass das Einzige, was die Beziehung ändert, die Bedeutung der
Zuordnung ist. Sie ist standardmäßig Unspecified, was die Datei zuordnet, einer
Maschine aber nichts darüber sagt, warum; für eine E-Rechnungs-Nutzlast setzen Sie
sie auf Data, damit ein Reader sie findet.
<?php
declare(strict_types=1);
use NextPDF\Core\Document;use NextPDF\Navigation\AFRelationship;
$document = Document::createStandalone();$document->addPage();$document->setFont('helvetica', 'B', 16);$document->cell(0, 12, 'Invoice INV-2026-0042', newLine: true);
// An UNTYPED associated file: the bytes are embedded AND the file spec is// added to the document catalog's /AF array, but the relationship says// nothing about why. A reader can open it; a machine cannot tell its role.// The relationship is left Unspecified (its default); the second argument is// the human-readable description. embedFile accepts the AFRelationship enum.$document->embedFile( '/srv/invoices/INV-2026-0042-source.docx', 'Original source document', AFRelationship::Unspecified,);
// A TYPED associated file: the invoice XML is declared as the DATA behind// the visible page. This is the relationship a hybrid e-invoice reader// looks for — the same intent the dedicated e-invoice embedder sets.// embedFileFromString takes the data, a filename, a description, and a// relationship as a PDF-name string ('/Data').$invoiceXml = $generateCiiXml(); // your ERP authors this; the engine never does$document->embedFileFromString( $invoiceXml, 'factur-x.xml', 'Factur-X invoice data', '/Data',);
$bytes = $document->getPdfData();Die '/Data'-Beziehung ist unverkennbar. Der erste Anhang – als Unspecified
belassen – ist gleichermaßen zugeordnet, nur ohne eine angegebene Bedeutung. Für
beide Aufrufe schreibt die Engine den eingebetteten Dateistream, fügt die Datei dem
EmbeddedFiles-Namensbaum hinzu, listet ihre Dateispezifikation im /AF-Array des
Dokumentkatalogs auf und erfasst die Beziehung, die Sie angegeben haben – sie wählt
keine für Sie aus. Diese Engine hat keinen Nur-Namensbaum-Modus: Jede Datei, die Sie
auf diese Weise einbetten, ist eine dokumentzugeordnete Datei, sodass die Beziehung
der einzige Hebel ist, den Sie kontrollieren.
Häufiges Missverständnis
Abschnitt betitelt „Häufiges Missverständnis“Die häufige Annahme ist, dass „eingebettet” und „zugeordnet” zwei Wörter für
dasselbe sind. Das sind sie nicht. Eingebettet bezieht sich auf die Speicherung –
die Bytes sind im PDF. Zugeordnet bezieht sich auf die Bindung – die
Dateispezifikation ist in einem /AF-Array an einem Teil des Dokuments aufgeführt,
und sie trägt eine AFRelationship. Im abstrakten PDF-Modell kann eine Datei in den
Namensbaum eingebettet werden, ohne jemals zugeordnet zu sein; der embedFile()-Pfad
von NextPDF belässt es nicht dabei – er schreibt stets die /AF-Zuordnung –, sodass
für diese Engine die offene Frage nie ist, ob eine Datei zugeordnet ist, sondern
was die Beziehung aussagt.
Eine zweite Falle: anzunehmen, ein Reader werde „herausfinden”, welcher Anhang die
Rechnung ist. Ein konformer Reader soll nicht raten. Er sucht nach der Datei, deren
Beziehung Data angibt. Belassen Sie die Beziehung als Unspecified, und Sie haben
die Nutzlast zugeordnet, der Maschine aber nichts Nützliches über ihre Rolle gesagt.
Grenzen und Abgrenzungen
Abschnitt betitelt „Grenzen und Abgrenzungen“Der Container-Mechanismus ist auf eine Weise mächtig, über die man ehrlich sein
sollte: embedFile() liest jeden Pfad, den der PHP-Prozess lesen kann. Das ist die
Funktion – und es ist zugleich die Grenze. Die Engine hängt die Bytes an, die ihr
gegeben werden; sie entscheidet nicht, und kann nicht für Sie entscheiden, ob ein
Pfad einer ist, den Sie offenzulegen beabsichtigt haben.
| Edition | Availability |
|---|---|
| Core |
|
| Pro | Not in this edition |
| Enterprise | Not in this edition |
Zwei weitere Grenzen, die es klar zu benennen gilt:
- Einbetten ist nicht Validieren. Die Engine trägt die Bytes, die Sie ihr geben. Ob das eingebettete XML eine konforme Rechnungsnutzlast ist, ist eine separate Frage, die ein Validator beantwortet – siehe die Rechnungsseite.
- Ein typisierter Anhang ist für sich genommen keine konforme Archivdatei. Die hybride Datei zu einem rechtlichen PDF/A-3-Dokument zu machen, erfordert den Archivmodus und eine unabhängige Konformitätsprüfung – siehe die Archivierungsseite.
Verwandte Dokumente
Abschnitt betitelt „Verwandte Dokumente“- Rechnungen und E-Rechnungen – der
Anwendungsfall, den dieser Mechanismus möglich macht: ein hybrides PDF, das eine
maschinenlesbare Rechnung als seine
Data-zugeordnete Datei trägt. - Archivierung und PDF/A – warum der Träger eine PDF/A-3-Datei ist und was Konformität verspricht und was nicht.
- Die Anatomie einer PDF-Datei – wo der Namensbaum und der Dokumentkatalog in der Dateistruktur sitzen.
- Streams und Filter – wie die Bytes einer eingebetteten Datei in einem Stream-Objekt gespeichert und komprimiert werden.
Glossar
Abschnitt betitelt „Glossar“- Eingebetteter Dateistream – ein PDF-Stream-Objekt, das die Bytes einer externen Datei enthält, mit einem Parameter-Dictionary, das ihre ursprüngliche Größe, Daten und eine Prüfsumme erfasst (ISO 32000-2 §7.11.4).
- EmbeddedFiles-Namensbaum – die sortierte Zuordnung im Dokumentkatalog, die eingebettete Dateien namentlich auflistet, sodass ein Reader Anhänge aufzählen kann, ohne das gesamte Dokument zu durchsuchen.
- Zugeordnete Datei – eine eingebettete Datei, die durch eine
/AF-Zuordnung (am Dokumentkatalog, einer Seite oder einem Objekt) an einen Teil des Dokuments gebunden ist und eineAFRelationshipträgt, die angibt, wie sie mit diesem Inhalt zusammenhängt; der dokumentweite Fall – die Dateispezifikation im/AF-Array des Katalogs – ist derjenige, auf den sich diese Seite konzentriert (ISO 32000-2 §14.13.3). - AFRelationship – der Dateispezifikationsschlüssel, dessen Wert die Beziehung
benennt (ISO 32000-2 §7.11.3). Er nimmt einen von acht Standardwerten an
(
Source,Data,Alternative,Supplement,EncryptedPayload,FormData,Schema,Unspecified) oder einen benutzerdefinierten Wert;Dataist der Wert, den eine hybride E-Rechnungs-Nutzlast verwendet. - PDF/A-3 – das ISO-19005-3-Archivprofil, das das Einbetten von Dateien jedes Formats erlaubt und so ein konformes hybrides Dokument ermöglicht.
- Hybride Rechnung – eine PDF-Datei, die zugleich eine menschenlesbare Seite und eine maschinenlesbare eingebettete Rechnungsnutzlast ist.