Pular para o conteúdo

Analise e inspecione fatos estruturais de um PDF

Esta receita usa o fallback Quick do inspetor do Core para ler fatos estruturais de um arquivo Portable Document Format (PDF). Com ela, você obtém a versão, a contagem de páginas, o sinalizador de criptografia, o sinalizador de assinatura, o sinalizador de anexo, o tamanho do arquivo e os sinalizadores de risco. O Quick é executado integralmente dentro do processo, sem o sidecar Spectrum e sem acesso à rede. Use-o para triagem rápida, não como validador.

Terminal window
composer require nextpdf/core:^3

Um arquivo PDF registra a versão no cabeçalho do arquivo (ISO 32000-2 §7.5.2). O trailer contém um identificador de arquivo (/ID) como duas byte strings (ISO 32000-2 §7.5.5). Quando há uma assinatura, um dicionário de assinatura armazena Cryptographic Message Syntax (CMS) SignedData codificado em Distinguished Encoding Rules (DER) em Contents (ISO 32000-2 §12.8.1). O fallback Quick usa uma varredura limitada dos bytes do documento para derivar a versão, uma estimativa da contagem de páginas e os sinalizadores de presença de criptografia, assinatura e anexo.

Crie new Inspector() e depois chame ->inspect(string $pdfData, InspectConfig::quick()). Ele retorna um InspectResult com $pdfVersion, $pageCount, $isEncrypted, $hasSigned, $hasAttachments, $fileSizeBytes, $riskFlags e o 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 programa autossuficiente é executado no harness do cookbook. Ele espelha examples/39-parse-and-inspect-pdf.php: constrói um pequeno PDF de várias páginas na memória, lê os fatos estruturais com o fallback Quick e roteia com base nesses fatos, nunca em um veredito de confiança. O ramo de roteamento é ilustrativo. Substitua-o pelo seu próprio pipeline, fila de verificação e quarentena.

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

Saída padrão (STDOUT) esperada (a versão e o tamanho dependem do build; o PDF de demonstração não está criptografado nem assinado e está livre de riscos):

PDF version : <version>
Pages : 2
Encrypted : no
Signed : no
Attachments : no
File size : <n> bytes
Risk flags : 0
Route: continue (no risks, unsigned, unencrypted)
  • O Quick é triagem, não validação. Ele relata o que está presente e o que está ausente. Ele não verifica assinaturas, não descriptografa conteúdo nem afirma conformidade. Trate o resultado como entrada de roteamento.
  • A contagem de páginas é uma estimativa. O fallback Quick conta os marcadores de objeto de página. Um grafo de objetos deliberadamente malformado pode distorcer a contagem. Use as profundidades com suporte do Spectrum quando precisar de uma contagem exata.
  • Standard/Full precisam do sidecar. new InspectConfig() (profundidade Standard) e InspectConfig::full() exigem o sidecar Spectrum. Eles lançam INSPECT-SIDECAR-001 quando ele está indisponível e não fazem downgrade silencioso para o Quick.
  • Entrada vazia. Passar uma string vazia lança uma exceção de inspeção com “PDF data must not be empty”.
  • Escopo do sinalizador de criptografia. O sinalizador reflete uma entrada /Encrypt no trailer. Um arquivo com esse sinalizador não é descriptografado pelo inspetor.

O fallback Quick usa uma varredura limitada, não uma análise completa. Use-o para pré-rotear grandes volumes de arquivos recebidos antes de um processamento mais pesado.

O inspetor é executado dentro do processo e lê apenas marcadores estruturais. Nenhum byte do documento sai do host e nenhum texto do documento é extraído. Um sinalizador de risco, como JavaScript incorporado, é um sinal consultivo para roteamento. Não é uma afirmação de que o arquivo é seguro ou inseguro.

DeclaraçãoEspecificaçãoCláusulareference_id
O cabeçalho do arquivo registra a versão do PDF.ISO 32000-2§7.5.2
O /ID do trailer é um identificador de arquivo composto por duas byte strings.ISO 32000-2§7.5.5
O Contents de um dicionário de assinatura contém CMS SignedData em DER.ISO 32000-2§12.8.1

Esta receita relata apenas fatos estruturais. Ela não afirma que o arquivo é válido, seguro ou conforme.

As profundidades de inspeção Standard e Full são executadas pelo sidecar Spectrum. Elas adicionam uma análise mais rica de objetos, fontes e imagens. O fallback Quick documentado aqui faz parte do Core e funciona offline.