Metadane: budowanie pakietu XMP i odczyt strumieniowy
W skrócie
Dział zatytułowany „W skrócie”Moduł Metadata jest warstwą Extensible Metadata Platform (XMP) w silniku. Buduje pakiet XMP przenoszony przez plik Portable Document Format (PDF) jako strumień metadanych. Odczytuje istniejący pakiet bez wczytywania całego dokumentu do pamięci. Emituje rozszerzenie XMP dla ścieżki audytu silnika.
Instalacja
Dział zatytułowany „Instalacja”composer require nextpdf/core:^3Przegląd koncepcyjny
Dział zatytułowany „Przegląd koncepcyjny”Plik PDF przechowuje metadane na poziomie dokumentu jako pakiet XMP w strumieniu metadanych dołączonym do katalogu dokumentu, zgodnie z opisem w ISO 32000-2 §14.3. Ten moduł odpowiada za tworzenie i odczytywanie tego pakietu. Jego powierzchnia jest celowo niewielka i ukierunkowana: trzy klasy w NextPDF\Metadata\Xmp.
XmpMetadataBuilder tworzy pakiet. Serializuje zestaw właściwości do prawidłowo uformowanego dokumentu XMP opakowanego w standardowe instrukcje przetwarzania <?xpacket?>. Używa kanonicznego globalnie unikalnego identyfikatora (GUID) pakietu oraz znacznika kolejności bajtów określonego przez specyfikację XMP. Wynikiem jest ciąg bajtów, który Writer osadza jako strumień metadanych — reprezentacja XMP wewnątrz PDF opisana w §14.3.
XmpStreamReader odczytuje pakiet. Zaprojektowano go z myślą o potencjalnie złośliwych danych wejściowych. Źródło jest strumieniowane porcjami po 64 KB do ograniczonego pliku tymczasowego przed parsowaniem. Podczas tego zapisu czytnik egzekwuje łączny limit bajtów. Mechanizm ładowania encji libxml jest ustawiany na null na czas parsowania, a następnie przywracany. Obecność DOCTYPE powoduje bezwarunkowe odrzucenie. iterateProperties() zwraca generator emitujący dla każdego elementu liścia krotki (namespaceUri, localName, textContent) bez budowania całego drzewa w pamięci; w danym momencie w parserze pozostaje tylko bieżący element i jego węzeł tekstowy. Pakiet przekraczający limit zgłasza PacketTooLargeException; nieprawidłowy Extensible Markup Language (XML), DOCTYPE lub dane wejściowe spoza UTF-8 powodują zgłoszenie InvalidConfigException.
XmpAuditFieldEmitter to rozszerzenie specyficzne dla silnika. Renderuje AuditReport do niestandardowego pola XMP w przestrzeni nazw nextpdfAudit, dzięki czemu audyt zgodności dokumentu jest przenoszony wraz z plikiem w postaci zgodnej ze standardami XMP, a nie jako osobny plik towarzyszący. Renderowany AuditReport nie jest tworzony przez emitter. Kod wywołujący aktywuje wzbogacanie, uruchamiając renderowanie w trybie CssRenderingMode::Audit z dostarczonym przez wywołującego auditCollector skonfigurowanym przez Config(auditCollector: ...). Kolektorem steruje kod wywołujący: zasila go, a emitter renderuje to, co kolektor zebrał. Ten komponent jest nowszy niż podstawowa powierzchnia XMP (@since 5.4.0). Builder i czytnik są dostępne od @since 2.0.0.
Powierzchnia API
Dział zatytułowany „Powierzchnia API”| Klasa | Kluczowe składowe | Rola |
|---|---|---|
XmpMetadataBuilder | build(): string, XPACKET_GUID, XPACKET_BOM | Serializuje zestaw właściwości do pakietu XMP (@since 2.0.0) |
XmpStreamReader | iterateProperties(mixed $source, int $byteCap = DEFAULT_BYTE_CAP): \Generator, DEFAULT_BYTE_CAP | Ograniczony, strumieniowy czytnik XMP odrzucający DOCTYPE (@since 2.0.0) |
PacketTooLargeException | rozszerza NextPdfException | Zgłaszany, gdy pakiet XMP przekroczy limit bajtów (@since 2.0.0) |
XmpAuditFieldEmitter | render(?AuditReport $report): string, NAMESPACE_URI | Renderuje ścieżkę audytu jako niestandardowe pole XMP (@since 5.4.0) |
Uruchom composer docs:generate-api-php -- --module=Metadata, aby wygenerować pełną tabelę PHPDoc.
Przykład kodu — szybki start
Dział zatytułowany „Przykład kodu — szybki start”Odczytaj strumieniowo właściwości z istniejącego pakietu XMP w granicach jawnego limitu bajtów.
<?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);}Przykład kodu — produkcja
Dział zatytułowany „Przykład kodu — produkcja”Odczytaj pakiet defensywnie i mapuj typowane błędy modułu na wynik na poziomie aplikacji, zamiast wypuszczać surowe błędy parsera na zewnątrz.
<?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; }}Przypadki brzegowe i pułapki
Dział zatytułowany „Przypadki brzegowe i pułapki”XmpStreamReaderbezwarunkowo odrzuca każdy DOCTYPE. Jest to zabezpieczenie przed XML External Entity (XXE), a nie kosmetyczna walidacja; pakiet, który wymaga DOCTYPE, nie jest akceptowany. Oczyść go wcześniej po stronie źródła.- Limit bajtów domyślnie wynosi 1 GiB (
DEFAULT_BYTE_CAP). Ta wartość domyślna to górny pułap, a nie zalecenie. Dla niezaufanych danych wejściowych przekaż ścisłybyteCap. iterateProperties()to generator. Odczytaj go jednokrotnie; dwukrotne iterowanie nie odtworzy wyników.- Czytnik ustawia mechanizm ładowania encji libxml na null na czas parsowania, a następnie go przywraca. Nie uruchamiaj go równolegle z innym parsowaniem opartym na libxml w tym samym żądaniu, jeśli to parsowanie zależy od mechanizmu ładowania encji.
XmpAuditFieldEmitter::render(null)jest poprawne i zwraca pusty wynik renderowania; null jakoAuditReportoznacza „brak audytu”, a nie błąd.
Wydajność
Dział zatytułowany „Wydajność”Builder ma złożoność liniową względem liczby właściwości. O zużyciu pamięci czytnika decyduje najdłuższy pojedynczy ciąg tekstu, a nie rozmiar dokumentu, ponieważ w parserze pozostaje tylko bieżący element; duże pakiety są strumieniowane zamiast wczytywane do pamięci. Domyślne referencyjne obciążenie mieści się w budżecie 1500 ms czasu rzeczywistego / 64 MB szczytowego zużycia. Profil odtwarzalności to structural: pakiet XMP zapisuje znaczniki czasu modyfikacji. Dwa przebiegi budowania tych samych logicznych metadanych różnią się w tych polach, choć ich struktura jest identyczna.
Uwagi dotyczące bezpieczeństwa
Dział zatytułowany „Uwagi dotyczące bezpieczeństwa”XmpStreamReader parsuje niezaufany XML i jest odpowiednio zabezpieczony. Strumieniowanie w porcjach z egzekwowanym limitem bajtów ogranicza atak typu odmowa usługi oparty na amplifikacji zużycia pamięci. Odrzucanie DOCTYPE blokuje XXE. LIBXML_NONET blokuje rozwiązywanie encji przez sieć. Dane wejściowe spoza UTF-8 są odrzucane. Mimo to dla każdego pakietu z zewnętrznego źródła ustaw byteCap odpowiedni dla wdrożenia, zamiast polegać na domyślnej wartości w gigabajtach. Traktuj wartości właściwości XMP jak niezaufane ciągi znaków, gdy ponownie trafiają do aplikacji. Zobacz model zagrożeń silnika w /modules/core/security/.
Zgodność
Dział zatytułowany „Zgodność”Pakiet tworzony przez XmpMetadataBuilder jest reprezentacją strumienia metadanych XMP wewnątrz PDF, zdefiniowaną w ISO 32000-2 §14.3 (). Sama forma serializacji XMP podlega specyfikacji XMP (ISO 16684-1), która nie znajduje się w weryfikowalnym korpusie cytowań. To wymaganie jest przywoływane przez numer, a nie przypięte do fragmentu. Są to fakty implementacyjne pochodzące z src/Metadata/Xmp/ i sprawdzane przez tests/Unit/Metadata/Xmp/. Pełna zgodność metadanych dla profilu (PDF/A, PDF/UA) jest weryfikowana przez zestawy oracle i golden opisane w /modules/core/conformance/.
Zobacz także
Dział zatytułowany „Zobacz także”- Moduł Document — drzewo DPart powiązane z Document Part Metadata (DPM).
- Moduł Audit — tworzy
AuditReportrenderowany przez emitter. - Moduł Writer — osadza pakiet jako strumień metadanych.
- Przegląd zgodności
- Model bezpieczeństwa silnika