Ir al contenido

Analizar e inspeccionar un PDF para obtener datos estructurales

Esta receta lee datos estructurales de un PDF mediante el respaldo Quick del inspector de Core. Incluye la versión, el recuento de páginas, el indicador de cifrado, el indicador de firma, el indicador de adjuntos, el tamaño de archivo y los indicadores de riesgo. Quick se ejecuta por completo dentro del proceso, sin el sidecar de Spectrum ni acceso a la red. Úsalo para triaje rápido, no como validador.

Ventana de terminal
composer require nextpdf/core:^3

Un PDF registra su versión en el encabezado del archivo (ISO 32000-2 §7.5.2). El tráiler contiene un identificador de archivo (/ID) formado por dos cadenas de bytes (ISO 32000-2 §7.5.5). Cuando existe una firma, se representa mediante un diccionario de firma cuyo Contents contiene CMS SignedData en DER (ISO 32000-2 §12.8.1). El respaldo Quick obtiene la versión, una estimación del recuento de páginas y los indicadores de presencia de cifrado, firma y adjuntos a partir de un escaneo acotado de los bytes del documento.

Crear new Inspector() y luego llamar a ->inspect(string $pdfData, InspectConfig::quick()). El resultado es un InspectResult con $pdfVersion, $pageCount, $isEncrypted, $hasSigned, $hasAttachments, $fileSizeBytes, $riskFlags y el método auxiliar 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',
);

Este es el programa autónomo que se ejecuta en el harness. Corresponde a examples/39-parse-and-inspect-pdf.php: construye en memoria un PDF pequeño de varias páginas, lee sus datos estructurales con el respaldo Quick y enruta según esos datos (nunca a partir de un veredicto de confianza). La rama de enrutamiento es ilustrativa. Conecta tu propio pipeline, cola de verificación y cuarentena.

<?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);

STDOUT esperado (la versión y el tamaño dependen de la compilación; el PDF de demostración no está cifrado, no está firmado y no tiene riesgos):

PDF version : <version>
Pages : 2
Encrypted : no
Signed : no
Attachments : no
File size : <n> bytes
Risk flags : 0
Route: continue (no risks, unsigned, unencrypted)
  • Quick es triaje, no validación. Informa qué está presente y qué está ausente. No verifica firmas, no descifra contenido ni afirma conformidad. Trata el resultado como entrada de enrutamiento.
  • El recuento de páginas es una estimación. El respaldo Quick cuenta los marcadores de objeto de página. Un grafo de objetos deliberadamente malformado puede sesgar el recuento. Usa las profundidades respaldadas por Spectrum cuando sea importante disponer de un recuento exacto.
  • Standard/Full necesitan el sidecar. new InspectConfig() (profundidad Standard) e InspectConfig::full() requieren el sidecar de Spectrum. Lanzan INSPECT-SIDECAR-001 cuando no está disponible y no se degradan en silencio a Quick.
  • Entrada vacía. Una cadena vacía lanza una excepción de inspección con «PDF data must not be empty».
  • Alcance del indicador de cifrado. El indicador refleja una entrada /Encrypt del tráiler. El inspector no descifra un archivo marcado.

El respaldo Quick es un escaneo acotado, no un análisis completo. Es adecuado para el preenrutamiento de grandes volúmenes de archivos entrantes antes de un procesamiento más pesado.

El inspector se ejecuta en el proceso y lee solo marcadores estructurales. Ningún byte del documento sale del host ni se extrae texto del documento. Un indicador de riesgo, por ejemplo JavaScript incrustado, es una señal informativa para el enrutamiento. No es una afirmación de que el archivo sea seguro o inseguro.

AfirmaciónEspecificaciónCláusulareference_id
El encabezado del archivo registra la versión del PDF.ISO 32000-2§7.5.2
El /ID del tráiler es un identificador de archivo formado por dos cadenas de bytes.ISO 32000-2§7.5.5
El Contents de un diccionario de firma contiene CMS SignedData en DER.ISO 32000-2§12.8.1

Esta receta informa de datos estructurales. No afirma que el archivo sea válido, seguro ni conforme.

Las profundidades de inspección Standard y Full se ejecutan mediante el sidecar de Spectrum. Esas profundidades añaden un análisis más detallado de objetos, fuentes e imágenes. El respaldo Quick documentado aquí es de Core y funciona sin conexión.