Metadata: XMP-pakket bouwen en streamend lezen
In een oogopslag
Sectie met titel “In een oogopslag”De Metadata-module vormt de Extensible Metadata Platform (XMP)-laag van de engine. De module bouwt het XMP-pakket dat een Portable Document Format (PDF)-bestand als metadatastream meedraagt. Ze leest een bestaand pakket zonder het hele document in het geheugen te laden en rendert ook de audit-trail-XMP-uitbreiding van de engine.
Installeren
Sectie met titel “Installeren”composer require nextpdf/core:^3Conceptueel overzicht
Sectie met titel “Conceptueel overzicht”Een PDF slaat metadata op documentniveau op als een XMP-pakket in een metadatastream die aan de documentcatalogus is gekoppeld, zoals beschreven in ISO 32000-2 §14.3. Deze module is verantwoordelijk voor het aanmaken en uitlezen van dat pakket. Het API-oppervlak is bewust klein en doelgericht: drie klassen onder NextPDF\Metadata\Xmp.
XmpMetadataBuilder produceert het pakket. De builder serialiseert een set eigenschappen naar een correct opgemaakt XMP-document, omsloten door de standaard <?xpacket?>-verwerkingsinstructies. De builder gebruikt de canonieke globally unique identifier (GUID) van het pakket en de byte-order-mark die door de XMP-specificatie zijn vastgelegd. De uitvoer is de bytestring die de Writer als metadatastream insluit: de in-PDF-XMP-representatie die in §14.3 wordt beschreven.
XmpStreamReader leest een pakket uit. De reader is ontworpen met kwaadaardige invoer als uitgangspunt. De bron wordt vóór het parseren in chunks van 64 KB naar een begrensd tijdelijk bestand gestreamd. Tijdens dat schrijven handhaaft de reader een totale bytelimiet. De libxml-entity-loader wordt voor het parseren op null gezet en daarna hersteld. Een DOCTYPE leidt tot een harde afwijzing. iterateProperties() geeft een generator terug die voor elk leaf-element (namespaceUri, localName, textContent)-tuples levert zonder de hele boom in het geheugen op te bouwen; op elk moment houdt de parser alleen het huidige element en de bijbehorende tekstnode vast. Een te groot pakket veroorzaakt PacketTooLargeException; onjuist opgemaakte Extensible Markup Language (XML), een DOCTYPE of niet-UTF-8-invoer veroorzaakt InvalidConfigException.
XmpAuditFieldEmitter is de engine-specifieke uitbreiding. De emitter rendert een AuditReport naar een aangepast XMP-veld onder de nextpdfAudit-namespace, zodat de conformiteitsaudit van een document als standaardconforme XMP met het bestand meereist in plaats van als losse bijlage. Het AuditReport dat de emitter rendert, wordt niet door de emitter zelf geproduceerd. De aanroeper activeert verrijking door te renderen onder CssRenderingMode::Audit met een door de aanroeper geleverde auditCollector die via Config(auditCollector: ...) is geconfigureerd. De aanroeper stuurt de collector aan: hij voedt hem, en de emitter rendert wat de collector heeft verzameld. De emitter is nieuwer dan het core-XMP-API-oppervlak (@since 5.4.0). De builder en reader zijn @since 2.0.0.
API-oppervlak
Sectie met titel “API-oppervlak”| Klasse | Belangrijkste leden | Rol |
|---|---|---|
XmpMetadataBuilder | build(): string, XPACKET_GUID, XPACKET_BOM | Serialiseert een set eigenschappen naar een XMP-pakket (@since 2.0.0) |
XmpStreamReader | iterateProperties(mixed $source, int $byteCap = DEFAULT_BYTE_CAP): \Generator, DEFAULT_BYTE_CAP | Begrensde, streamende XMP-reader die DOCTYPE afwijst (@since 2.0.0) |
PacketTooLargeException | breidt NextPdfException uit | Wordt gegooid wanneer een XMP-pakket de bytelimiet overschrijdt (@since 2.0.0) |
XmpAuditFieldEmitter | render(?AuditReport $report): string, NAMESPACE_URI | Rendert de audit-trail als een aangepast XMP-veld (@since 5.4.0) |
Voer composer docs:generate-api-php -- --module=Metadata uit om de volledige PHPDoc-tabel te genereren.
Codevoorbeeld — snel aan de slag
Sectie met titel “Codevoorbeeld — snel aan de slag”Stream eigenschappen uit een bestaand XMP-pakket onder een expliciete bytelimiet.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Metadata\Xmp\XmpStreamReader;
$reader = new XmpStreamReader();
foreach ($reader->iterateProperties(file_get_contents('/srv/in/xmp.xml'), byteCap: 1_048_576) as [$ns, $name, $value]) { printf("%s:%s = %s\n", $ns, $name, $value);}Codevoorbeeld — productie
Sectie met titel “Codevoorbeeld — productie”Lees een pakket defensief en wijs de getypeerde fouten van de module toe aan een uitkomst op applicatieniveau, in plaats van onbewerkte parserfouten te laten ontsnappen.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Exception\InvalidConfigException;use NextPDF\Metadata\Xmp\PacketTooLargeException;use NextPDF\Metadata\Xmp\XmpStreamReader;use Psr\Log\LoggerInterface;
final readonly class XmpIngestService{ public function __construct( private XmpStreamReader $reader, private LoggerInterface $logger, ) {}
/** * @param resource|string $source A stream resource or XMP byte string. * * @return array<string, string> Flattened "ns:name" => value map. */ public function ingest(mixed $source): array { $properties = [];
try { // Cap untrusted XMP at 4 MB regardless of the 1 GiB default. foreach ($this->reader->iterateProperties($source, byteCap: 4_194_304) as [$ns, $name, $value]) { $properties["{$ns}:{$name}"] = $value; } } catch (PacketTooLargeException $e) { $this->logger->warning('XMP packet exceeded ingest cap; rejected.', ['error' => $e->getMessage()]);
return []; } catch (InvalidConfigException $e) { $this->logger->warning('XMP packet malformed or unsafe; rejected.', ['error' => $e->getMessage()]);
return []; }
return $properties; }}Randgevallen en valkuilen
Sectie met titel “Randgevallen en valkuilen”XmpStreamReaderwijst elke DOCTYPE rechtstreeks af. Dit is een verdediging tegen XML External Entity (XXE), geen validatieformaliteit; een pakket dat een DOCTYPE nodig heeft, wordt niet geaccepteerd. Schoon het stroomopwaarts op.- De bytelimiet is standaard 1 GiB (
DEFAULT_BYTE_CAP). Die standaardwaarde is een bovengrens, geen aanbeveling. Geef een strakkebyteCapmee voor niet-vertrouwde invoer. iterateProperties()is een generator. Verbruik hem eenmalig; een tweede iteratie kan niet worden herhaald.- De reader zet de libxml-entity-loader voor het parseren op null en herstelt deze daarna. Voer hem niet gelijktijdig uit met ander op libxml gebaseerd parseren binnen hetzelfde verzoek wanneer dat parseren afhankelijk is van de entity-loader.
XmpAuditFieldEmitter::render(null)is geldig en levert een lege renderuitvoer op; een null-AuditReportbetekent “geen audit”, geen fout.
Prestaties
Sectie met titel “Prestaties”De builder is lineair in het aantal eigenschappen. Het geheugengebruik van de reader wordt bepaald door de langste afzonderlijke tekstreeks, niet door de documentgrootte, omdat alleen het huidige element in de parser aanwezig is; grote pakketten worden gestreamd in plaats van in het geheugen geladen. De standaard referentiebelasting blijft binnen een budget van 1500 ms wandkloktijd / 64 MB piek. Het reproduceerbaarheidsprofiel is structural: een XMP-pakket legt wijzigingstijdstempels vast. Twee builds van dezelfde logische metadata verschillen in die velden, terwijl hun structuur identiek is.
Beveiligingsopmerkingen
Sectie met titel “Beveiligingsopmerkingen”XmpStreamReader parseert niet-vertrouwde XML en is daarop gehard. Streamende chunking met een afgedwongen bytelimiet beperkt denial-of-service door geheugenversterking. Het afwijzen van DOCTYPE blokkeert XXE. LIBXML_NONET blokkeert het resolven van entiteiten via het netwerk. Niet-UTF-8-invoer wordt geweigerd. Stel toch voor elk extern verkregen pakket een bij de deployment passende byteCap in, in plaats van te vertrouwen op de gigabyte-standaardwaarde. Behandel XMP-eigenschapswaarden als niet-vertrouwde strings wanneer ze opnieuw de applicatie binnenkomen. Zie het dreigingsmodel van de engine in /modules/core/security/.
Conformiteit
Sectie met titel “Conformiteit”Het pakket dat XmpMetadataBuilder produceert, is de in-PDF-XMP-metadatastream-representatie die is gedefinieerd in ISO 32000-2 §14.3 (). De XMP-serialisatievorm zelf wordt geregeld door de XMP-specificatie (ISO 16684-1), die niet in het verifieerbare citatiecorpus zit. Naar die eis wordt op nummer verwezen en niet vastgepind op een chunk. Deze implementatiefeiten worden geproduceerd door src/Metadata/Xmp/ en getoetst door tests/Unit/Metadata/Xmp/. End-to-end-metadataconformiteit voor een profiel (PDF/A, PDF/UA) wordt gevalideerd door de oracle- en golden-suites die worden beschreven in /modules/core/conformance/.
Zie ook
Sectie met titel “Zie ook”- Document-module — de DPart-boom die is gekoppeld aan Document Part Metadata (DPM).
- Audit-module — produceert het
AuditReportdat de emitter rendert. - Writer-module — sluit het pakket in als metadatastream.
- Conformiteitsoverzicht
- Beveiligingsmodel van de engine