Analyser et inspecter un PDF pour en extraire des faits structurels
Cette recette lit les faits structurels d’un PDF au moyen du repli Quick de l’inspecteur Core : version, nombre de pages, indicateurs de chiffrement, de signature et de pièces jointes, taille du fichier et indicateurs de risque. Quick s’exécute entièrement dans le processus, sans sidecar Spectrum ni réseau. Utilise-le pour un tri rapide, pas comme validateur.
Installation
Section intitulée « Installation »composer require nextpdf/core:^3Vue d’ensemble conceptuelle
Section intitulée « Vue d’ensemble conceptuelle »Un PDF enregistre sa version dans l’en-tête du fichier (ISO 32000-2 §7.5.2). La section finale (trailer) contient un identifiant de fichier (/ID) composé de deux chaînes d’octets (ISO 32000-2 §7.5.5). Lorsqu’une signature est présente, elle prend la forme d’un dictionnaire de signature dont l’entrée Contents contient des données CMS SignedData au format DER (ISO 32000-2 §12.8.1). Le repli Quick dérive la version, une estimation du nombre de pages ainsi que les indicateurs de présence de chiffrement, de signature et de pièces jointes au moyen d’une analyse bornée des octets du document.
Surface d’API
Section intitulée « Surface d’API »Appelle new Inspector(), puis ->inspect(string $pdfData, InspectConfig::quick()). Le résultat est un InspectResult qui expose $pdfVersion, $pageCount, $isEncrypted, $hasSigned, $hasAttachments, $fileSizeBytes, $riskFlags, et l’utilitaire hasRisks().
Exemple de code — Démarrage rapide
Section intitulée « Exemple de code — Démarrage rapide »<?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',);Exemple de code — Production
Section intitulée « Exemple de code — Production »Voici le programme autonome, exécutable par le harnais. Il reflète examples/39-parse-and-inspect-pdf.php : il construit un petit PDF de plusieurs pages en mémoire, lit ses faits structurels grâce au repli Quick et oriente le traitement d’après ces faits (jamais d’après un verdict de confiance). La branche d’orientation est fournie à titre d’illustration. Branche ton propre pipeline, ta file d’attente de vérification et ta mise en quarantaine.
<?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);Sortie STDOUT attendue (la version et la taille dépendent de la build ; le PDF de démonstration est non chiffré, non signé et sans risque) :
PDF version : <version>Pages : 2Encrypted : noSigned : noAttachments : noFile size : <n> bytesRisk flags : 0Route: continue (no risks, unsigned, unencrypted)Cas limites et pièges
Section intitulée « Cas limites et pièges »- Quick relève du tri, pas de la validation. Il indique ce qui est présent et ce qui est absent. Il ne vérifie pas les signatures, ne déchiffre pas le contenu et n’affirme aucune conformité. Traite le résultat comme une donnée d’orientation.
- Le nombre de pages est une estimation. Le repli Quick compte les marqueurs d’objets de page. Un graphe d’objets délibérément mal formé peut fausser le décompte. Utilise les profondeurs adossées à Spectrum lorsque l’exactitude du décompte compte.
- Standard/Full nécessitent le sidecar.
new InspectConfig()(profondeurStandard) etInspectConfig::full()nécessitent le sidecar Spectrum. Ces configurations lèventINSPECT-SIDECAR-001lorsqu’il est indisponible, et elles ne se rabattent pas silencieusement sur Quick. - Entrée vide. Une chaîne vide lève une exception d’inspection avec le message « PDF data must not be empty ».
- Portée de l’indicateur de chiffrement. L’indicateur reflète une entrée
/Encryptde la section finale (trailer). Un fichier marqué ainsi n’est pas déchiffré par l’inspecteur.
Performance
Section intitulée « Performance »Le repli Quick effectue une analyse bornée, pas une analyse complète. Il convient au pré-routage à fort volume des fichiers entrants avant un traitement plus lourd.
Notes de sécurité
Section intitulée « Notes de sécurité »L’inspecteur s’exécute dans le processus et ne lit que des marqueurs structurels. Aucun octet du document ne quitte l’hôte, et aucun texte du document n’est extrait. Un indicateur de risque, par exemple du JavaScript intégré, est un signal consultatif pour l’orientation. Il ne constitue pas une affirmation que le fichier est sûr ou dangereux.
Conformité
Section intitulée « Conformité »| Énoncé | Spécification | Article | reference_id |
|---|---|---|---|
| L’en-tête du fichier enregistre la version du PDF. | ISO 32000-2 | §7.5.2 | |
Le /ID de la section finale est un identifiant de fichier composé de deux chaînes d’octets. | ISO 32000-2 | §7.5.5 | |
L’entrée Contents d’un dictionnaire de signature contient des données CMS SignedData au format DER. | ISO 32000-2 | §12.8.1 |
Cette recette rapporte des faits structurels. Elle n’affirme pas que le fichier est valide, sûr ou conforme.
Contexte commercial
Section intitulée « Contexte commercial »Les profondeurs d’inspection Standard et Full passent par le sidecar Spectrum. Elles ajoutent une analyse plus riche des objets, des polices et des images. Le repli Quick documenté ici relève de Core et fonctionne hors ligne.