Przejdź do głównej zawartości

Analiza i inspekcja faktów strukturalnych pliku PDF

Ten przepis wykorzystuje rezerwowy tryb Quick w inspektorze Core do odczytywania faktów strukturalnych z pliku w formacie Portable Document Format (PDF). Wynik obejmuje wersję, liczbę stron, flagę szyfrowania, flagę podpisu, flagę załączników, rozmiar pliku oraz flagi ryzyka. Tryb Quick działa w całości w tym samym procesie, bez sidecara Spectrum i bez dostępu do sieci. Służy do szybkiej selekcji, nie do walidacji.

Okno terminala
composer require nextpdf/core:^3

Wersja pliku PDF jest zapisana w nagłówku pliku (ISO 32000-2 §7.5.2). Trailer zawiera identyfikator pliku (/ID) złożony z dwóch ciągów bajtów (ISO 32000-2 §7.5.5). Jeśli podpis jest obecny, słownik podpisu przechowuje w Contents strukturę Cryptographic Message Syntax (CMS) SignedData zakodowaną zgodnie z Distinguished Encoding Rules (DER) (ISO 32000-2 §12.8.1). Rezerwowy tryb Quick korzysta z ograniczonego skanowania bajtów dokumentu, aby ustalić wersję, szacunkową liczbę stron oraz flagi obecności szyfrowania, podpisu i załączników.

Utwórz new Inspector(), a następnie wywołaj ->inspect(string $pdfData, InspectConfig::quick()). Metoda zwraca obiekt InspectResult z polami $pdfVersion, $pageCount, $isEncrypted, $hasSigned, $hasAttachments, $fileSizeBytes, $riskFlags oraz metodą pomocniczą hasRisks().

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Inspect\InspectConfig;
use NextPDF\Inspect\Inspector;
$pdf = file_get_contents(__DIR__ . '/document.pdf');
$result = (new Inspector())->inspect($pdf, InspectConfig::quick());
printf(
"v%s, %d page(s), encrypted=%s, signed=%s\n",
$result->pdfVersion ?? '?',
$result->pageCount,
$result->isEncrypted ? 'yes' : 'no',
$result->hasSigned ? 'yes' : 'no',
);

Ten samodzielny program działa w środowisku testowym dla przepisów. Odpowiada examples/39-parse-and-inspect-pdf.php: buduje w pamięci niewielki, wielostronicowy plik PDF, odczytuje jego fakty strukturalne za pomocą rezerwowego trybu Quick i kieruje przetwarzaniem na podstawie tych faktów, nigdy na podstawie werdyktu zaufania. Gałąź kierowania ma charakter poglądowy. Zastąp ją własnym potokiem, kolejką weryfikatora oraz kwarantanną.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Inspect\InspectConfig;
use NextPDF\Inspect\Inspector;
// A self-contained input so the program runs with no external file.
$doc = Document::createStandalone();
$doc->setTitle('Parse-and-inspect demo');
$doc->setAuthor('NextPDF Cookbook');
$doc->addPage();
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'Page one of the parse-and-inspect demonstration.', newLine: true);
$doc->addPage();
$doc->cell(0, 10, 'Page two.', newLine: true);
$pdf = $doc->getPdfData();
$result = (new Inspector())->inspect($pdf, InspectConfig::quick());
echo 'PDF version : ' . ($result->pdfVersion ?? 'unknown') . "\n";
echo 'Pages : ' . $result->pageCount . "\n";
echo 'Encrypted : ' . ($result->isEncrypted ? 'yes' : 'no') . "\n";
echo 'Signed : ' . ($result->hasSigned ? 'yes' : 'no') . "\n";
echo 'Attachments : ' . ($result->hasAttachments ? 'yes' : 'no') . "\n";
echo 'File size : ' . $result->fileSizeBytes . " bytes\n";
echo 'Risk flags : ' . ($result->hasRisks() ? count($result->riskFlags) : 0) . "\n";
// Route on structural facts, not trust verdicts. Replace these calls with
// your own pipeline / verifier queue / quarantine.
if ($result->isEncrypted) {
// $pipeline->decryptThenContinue($pdf);
echo "Route: decrypt-then-continue\n";
} elseif ($result->hasSigned) {
// $verifierQueue->enqueue($pdf); // see the signature-inspect recipe
echo "Route: enqueue for cryptographic verification\n";
} elseif ($result->hasRisks()) {
// $quarantine->hold($pdf, $result->riskFlags);
echo "Route: quarantine (risk flags present)\n";
} else {
// $pipeline->continue($pdf);
echo "Route: continue (no risks, unsigned, unencrypted)\n";
}
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script under the
// semantic profile; emit the document to the side-channel.
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
file_put_contents($out !== false && $out !== '' ? $out : __DIR__ . '/inspected.pdf', $pdf);

Oczekiwane wyjście standardowe (STDOUT) (wersja i rozmiar zależą od kompilacji; demonstracyjny plik PDF jest nieszyfrowany, niepodpisany i nie zawiera flag ryzyka):

PDF version : <version>
Pages : 2
Encrypted : no
Signed : no
Attachments : no
File size : <n> bytes
Risk flags : 0
Route: continue (no risks, unsigned, unencrypted)
  • Tryb Quick to selekcja, a nie walidacja. Informuje, co jest obecne, a czego brakuje. Nie weryfikuje podpisów, nie odszyfrowuje treści ani nie potwierdza zgodności. Traktuj wynik jako dane wejściowe do kierowania przetwarzaniem.
  • Liczba stron jest szacunkowa. Rezerwowy tryb Quick zlicza znaczniki obiektów stron. Celowo zniekształcony graf obiektów może zafałszować tę liczbę. Jeśli potrzebna jest dokładna liczba, użyj poziomów głębi opartych na Spectrum.
  • Tryby Standard/Full wymagają sidecara. new InspectConfig() (głębia Standard) oraz InspectConfig::full() wymagają sidecara Spectrum. Jeśli jest on niedostępny, zgłaszają INSPECT-SIDECAR-001 i nie przechodzą po cichu do trybu Quick.
  • Puste dane wejściowe. Przekazanie pustego ciągu znaków powoduje zgłoszenie wyjątku inspekcji z komunikatem „PDF data must not be empty” (dane PDF nie mogą być puste).
  • Zakres flagi szyfrowania. Flaga odzwierciedla wpis /Encrypt w trailerze. Plik oznaczony tą flagą nie jest odszyfrowywany przez inspektor.

Rezerwowy tryb Quick używa ograniczonego skanowania, a nie pełnego parsowania. Stosuj go do wstępnego kierowania dużej liczby przychodzących plików przed cięższym przetwarzaniem.

Inspektor działa w tym samym procesie i odczytuje wyłącznie znaczniki strukturalne. Żadne bajty dokumentu nie opuszczają hosta, a z dokumentu nie jest wyodrębniany żaden tekst. Flaga ryzyka, na przykład osadzony JavaScript, jest sygnałem doradczym używanym do kierowania przetwarzaniem. Nie jest to stwierdzenie, że plik jest bezpieczny lub niebezpieczny.

StwierdzenieSpecyfikacjaKlauzulareference_id
Nagłówek pliku zapisuje wersję PDF.ISO 32000-2§7.5.2
Wpis /ID w trailerze jest identyfikatorem pliku złożonym z dwóch ciągów bajtów.ISO 32000-2§7.5.5
Wpis Contents słownika podpisu przechowuje strukturę CMS SignedData w kodowaniu DER.ISO 32000-2§12.8.1

Ten przepis zgłasza wyłącznie fakty strukturalne. Nie stwierdza, że plik jest prawidłowy, bezpieczny ani zgodny.

Poziomy głębi inspekcji Standard i Full działają za pośrednictwem sidecara Spectrum. Zapewniają bogatszą analizę obiektów, czcionek i obrazów. Opisany tutaj rezerwowy tryb Quick jest częścią Core i działa offline.