Zum Inhalt springen

Contracts / Extraktion

Die Extraction-Domäne enthält die Verträge zum Lesen und Validieren von PDFs sowie zum Überführen ihrer Inhalte in strukturierte Daten. Dazu gehören der Inspector, die Compliance-Validatoren, der PDF/A-Manager, die Verträge für importierte Objekte, die Verträge für Embedding und Vektorindex sowie der Unter-Namespace des E-Rechnungs-Validators.

Terminal-Fenster
composer require nextpdf/core:^3

InspectorInterface liest ein rohes PDF und liefert ein strukturiertes InspectResult. Das Ergebnis listet die Objekte in der Datei auf. Verwenden Sie es für jedes Werkzeug, das ein PDF liest, das nicht von der Engine geschrieben wurde.

ExternalComplianceValidatorInterface stellt die Brücke zu einem externen Prüfer wie veraPDF bereit. Der Prüfer prüft PDF/A und PDF/UA. Die Null-Variante liefert ein Ergebnis „nicht verfügbar“, wenn kein Prüfer konfiguriert ist. Eine Site ohne veraPDF bleibt damit weiterhin lauffähig. ProfileValidatorInterface prüft die Laufzeitumgebung gegen ein Deployment-Profil. Es berücksichtigt erforderliche und empfohlene Erweiterungen und liefert einen typisierten Befund.

PdfAManagerInterface hält eine PDF/A-Datei während des Schreibens spezifikationskonform. Es blockiert JavaScript, JavaScript-Formularaktionen und die integrierte Verschlüsselung. PDF/A verbietet alle drei. Außerdem prüft es, dass jede Schriftart eingebettet ist, setzt spezifikationskonforme Metadaten und schreibt die benötigten Objekte vor dem Katalog. Die konkrete Klasse ist in der Pro-Edition enthalten. Core findet sie mit class_exists() und castet sie auf den Vertrag. Die Open-Source-Engine hat damit keine kostenpflichtige Abhängigkeit.

Zwei Verträge decken importierte Objekte ab: ImportedFormObjectInterface und EmbeddedPdfObjectInterface. Sie bieten typisierten Zugriff auf Objekte, die aus einem bestehenden PDF gelesen wurden. Die Engine kann sie anschließend erneut einbetten. Ein verlustfreier Pfad bewahrt die rohen Dictionary-Bytes. Ein Fallback-Pfad liefert ein geparstes Dictionary-Array für Objekte, die aus Objekt-Streams stammen. Jedes erneut eingebettete Objekt ist ein indirektes PDF-Objekt. Eine Objektnummer und eine Generationsnummer benennen es — ISO 32000-2 §7.3.10.

Die Embedding-Verträge dienen der Suche. EmbeddingServiceInterface wandelt Text in einen dichten Vektor um. Es meldet die Modellgröße und den Modellnamen, damit sich Aufrufer zur Laufzeit anpassen können. Die Pro-Edition betreibt ein CPU-Modell, die Enterprise-Edition ein GPU-Modell. VectorIndexInterface baut einen Nächste-Nachbarn-Index auf und durchsucht ihn. Es ist der kleine In-Process-Index für die Core-Nutzung. Größere Suche liegt in einem Enterprise-exklusiven Vertrag.

Die Gruppe EInvoice enthält den editionsübergreifenden E-Rechnungs-Prüfer. ValidatorInterface führt Vorabprüfungen an einer CII- oder UBL-Nutzlast durch. SchematronRunnerInterface führt den Geschäftsregel-Durchlauf aus. ValidationResult sammelt Befunde und Regelverstöße. Der Prüfer muss fehlerhafte Eingaben mit einem Ergebnis ablehnen, nicht mit einer Exception. Außerdem muss er sich gegen DOCTYPE-Deklarationen und überdimensionierte Nutzlasten absichern.

TypArtWichtige MitgliederStabilitätSeit
InspectorInterfaceinterfaceinspect(string, InspectConfig): InspectResultexperimentell2.2.0
ExternalComplianceValidatorInterfaceinterfacevalidate(string, ComplianceFlavour), isAvailable()experimentell2.4.0
ProfileValidatorInterfaceinterfacevalidate(DeploymentProfile): DeploymentProfileResultexperimentell2.4.0
PdfAManagerInterfaceinterfacevalidateNoJavaScript(), validateFont(), validateNoEncryption(), applyOutputProfile(), writeRequiredObjects()stabil1.10.0
ImportedFormObjectInterfaceinterfacegetWidth(), getHeight(), getEmbeddedObjects(), getResourcesDict(), getMediaBox(), getContentStream()stabil1.8.0
EmbeddedPdfObjectInterfaceinterfacegetRawDictionaryBytes(), getRawStreamData(), getDictionary()stabil1.8.0
EmbeddingServiceInterfaceinterfaceembed(), batchEmbed(), getDimension(), getModelName()experimentell2.1.0
VectorIndexInterfaceinterfacebuild(), search(), delete(), count()experimentell2.1.0
EInvoice\ValidatorInterfaceinterfacevalidate(string, ValidatorContext): ValidationResultexperimentell5.1.0
EInvoice\ValidationResultfinal readonly class$isValid, getErrors(), getWarnings(), fail()experimentell5.1.0

Zusätzlich veröffentlicht der Namespace EInvoice SchematronRunnerInterface, ProfileInterface, ValidationFinding, RuleViolation sowie die Enums ProfileType, RuleSeverity und ValidationFindingLevel.

examples/contracts/extraction-quickstart.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\InspectorInterface;
use NextPDF\Inspect\InspectConfig;
/**
* Inspect a PDF and report its object count.
*
* @param InspectorInterface $inspector A configured inspector.
* @param string $pdfData Raw PDF bytes.
*/
function describe(InspectorInterface $inspector, string $pdfData): \NextPDF\Inspect\InspectResult
{
return $inspector->inspect($pdfData, new InspectConfig());
}

Die Funktion hängt vom Vertrag ab; jede Inspector-Implementierung erfüllt ihn.

examples/contracts/extraction-production.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\EInvoice\ValidatorInterface;
use NextPDF\Contracts\EInvoice\ValidatorContext;
use NextPDF\Contracts\ExternalComplianceValidatorInterface;
use NextPDF\ValueObjects\ComplianceFlavour;
use Psr\Log\LoggerInterface;
final readonly class InvoiceConformanceService
{
public function __construct(
private ValidatorInterface $invoiceValidator,
private ExternalComplianceValidatorInterface $pdfaValidator,
private LoggerInterface $logger,
) {}
/**
* Validate the invoice XML, then the PDF/A-3 carrier.
*
* @param string $xml The CII or UBL invoice payload.
* @param string $pdfPath Absolute path to the PDF/A-3 carrier.
*/
public function validate(string $xml, string $pdfPath, ValidatorContext $ctx): bool
{
$result = $this->invoiceValidator->validate($xml, $ctx);
if (!$result->isValid) {
$this->logger->warning('Invoice XML invalid', [
'errors' => \count($result->getErrors()),
]);
return false;
}
if (!$this->pdfaValidator->isAvailable()) {
$this->logger->info('PDF/A validator unavailable; skipping carrier check.');
return true;
}
$carrier = $this->pdfaValidator->validate($pdfPath, ComplianceFlavour::PdfA3b);
return $carrier->isConformant();
}
}

Der Service behandelt den Fall eines nicht verfügbaren Validators ausdrücklich, anstatt anzunehmen, dass ein Validator vorhanden ist.

  • EInvoice\ValidatorInterface::validate() liefert für fehlerhafte Eingaben ein fehlschlagendes ValidationResult. Es wirft bei Wohlgeformtheitsverstößen keine Exception. Prüfen Sie $isValid und umschließen Sie den Aufruf für diesen Fall nicht mit einem try/catch.
  • Prüfen Sie ExternalComplianceValidatorInterface::isAvailable(), bevor Sie sich auf einen Befund verlassen. Die Null-Implementierung liefert „nicht verfügbar“. Wenn Sie dies als „nicht konform“ behandeln, entstehen falsche Negative.
  • EmbeddedPdfObjectInterface::getRawDictionaryBytes() liefert null für Objekte, die aus einem Objekt-Stream stammen. Greifen Sie auf getDictionary() zurück. Gehen Sie nicht davon aus, dass rohe Bytes existieren.
  • EmbeddingServiceInterface::getDimension() unterscheidet sich je nach Stufe. Code, der einen Vektor fester Breite allokiert, muss die Dimension zur Laufzeit lesen, anstatt sie fest zu verdrahten.
  • VectorIndexInterface::build() erfordert, dass die Vektor- und die ID-Liste gleich lang sind und einheitliche Dimensionen haben. Eine Abweichung löst eine InvalidArgumentException aus. Validieren Sie die Eingaben vor dem Aufbau.

Die Kosten für Inspektion und Validierung skalieren mit der Dokumentgröße und der Objektzahl. Das performance_budget von 1500 ms Wall-Time und 64 MB Spitzenverbrauch deckt ein einzelnes mittelgroßes Dokument ab. Bei einem externen veraPDF-Aufruf kommt die eigene Prozesszeit des Validators hinzu. Diese Prozesszeit liegt außerhalb des Engine-Budgets und sollte außerhalb des Anfragepfads anfallen. Die Embedding-Kosten skalieren mit der Textlänge und sind in einem Batch deutlich günstiger als in einer Schleife, besonders bei einem GPU-Modell. Verwenden Sie bevorzugt batchEmbed(). Die Vektorsuche ist für den In-Process-Index sublinear zur Indexgröße. Das Reproduzierbarkeitsprofil ist structural. Ein Validierungsbericht erfasst einen Zeitstempel und einen Umgebungsfingerabdruck. Zwei Läufe unterscheiden sich in diesen Feldern, während der Konformitätsbefund identisch bleibt.

Die Extraktion liest Dokumente, die die Engine nicht erstellt hat; jede Eingabe ist daher nicht vertrauenswürdig. Der Inspector und der E-Rechnungs-Validator parsen beide extern bereitgestellte Bytes. Der E-Rechnungs-Validator muss DOCTYPE-Deklarationen, überdimensionierte Nutzlasten und Nutzlasten mit verbotenen Steuerzeichen vor dem Parsen abfangen, um XML-External-Entity- und Billion-Laughs-Angriffe zu verhindern. Das erneute Einbetten importierter Objekte kopiert Bytes aus einem fremden PDF. Ein bösartiges Quellobjekt kann feindseligen Inhalt tragen; daher bewahrt das erneute Einbetten die Bytes, ohne sie auszuführen. Die PDF/A-Durchsetzung entfernt JavaScript und Aktionen. Der PDF/A-Manager lehnt JavaScript und Verschlüsselung ab, weil beide im Profil verboten sind und in einem langlebigen Archivdokument Missbrauchsvektoren darstellen. Behandeln Sie inspizierten Inhalt, importierte Objekte und Rechnungs-XML durchgängig als feindselige Eingabe.

AussageStandardAbschnittNachweis
PDF/A-4 verbietet JavaScript und JavaScript-Formularaktionen; der PDF/A-Manager lehnt beide ab.ISO 19005-4§6.7.1per Klausel zitiert (nicht im Korpus)
Jedes erneut eingebettete Objekt ist ein indirektes PDF-Objekt, identifiziert durch Objektnummer und Generation.ISO 32000-2§7.3.10

ISO 19005-4 wird per Klausel referenziert. Es ist nicht im überprüfbaren Zitat-Korpus enthalten; daher wird keine reference_id erfasst. Die Aussage zum indirekten Objekt aus ISO 32000-2 ist im Glossar verankert. Beide Aussagen sind paraphrasiert. Die Engine gibt keinen normativen Text wieder.

Core definiert die Extraction-Verträge und friert sie ein. Der Produktionscode hinter PdfAManagerInterface, EmbeddingServiceInterface und VectorIndexInterface wird in der Pro- und der Enterprise-Edition ausgeliefert, einschließlich CPU- und GPU-Embedding-Modellen und dem vollständigen PDF/A-Durchsetzungspfad. Core löst diese Implementierungen zur Laufzeit mit class_exists() auf. Die Open-Source-Engine trägt daher keine kommerzielle Abhängigkeit, und die API ändert sich beim Upgrade nicht.